Merge "Revert "Check that API is up-to-date when building java_sdk_library""
diff --git a/.gitignore b/.gitignore
index a09c56d..45884c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
/.idea
+*.iml
diff --git a/OWNERS b/OWNERS
index 0662016..730db7a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -26,6 +26,6 @@
jingwen@google.com
# EMEA
-hansson@google.com
+hansson@google.com #{LAST_RESORT_SUGGESTION}
lberki@google.com
-paulduffin@google.com
+paulduffin@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/android/Android.bp b/android/Android.bp
index 8eb55d2..e0ad58f 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -38,7 +38,9 @@
"bazel_paths.go",
"buildinfo_prop.go",
"config.go",
+ "test_config.go",
"config_bp2build.go",
+ "configured_jars.go",
"csuite_config.go",
"deapexer.go",
"defaults.go",
@@ -88,6 +90,7 @@
"test_asserts.go",
"test_suites.go",
"testing.go",
+ "updatable_modules.go",
"util.go",
"variable.go",
"visibility.go",
@@ -98,6 +101,7 @@
"apex_test.go",
"arch_test.go",
"bazel_handler_test.go",
+ "bazel_paths_test.go",
"bazel_test.go",
"config_test.go",
"config_bp2build_test.go",
@@ -107,6 +111,7 @@
"deptag_test.go",
"expand_test.go",
"fixture_test.go",
+ "gen_notice_test.go",
"license_kind_test.go",
"license_test.go",
"licenses_test.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 0cb6946..1f6ecb5 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -38,108 +38,122 @@
var (
Bp2buildDefaultConfig = Bp2BuildConfig{
"art/libartpalette": Bp2BuildDefaultTrueRecursively,
+ "art/libartbase": Bp2BuildDefaultTrueRecursively,
"art/libdexfile": Bp2BuildDefaultTrueRecursively,
"art/libnativebridge": Bp2BuildDefaultTrueRecursively,
"art/runtime": Bp2BuildDefaultTrueRecursively,
"art/tools": Bp2BuildDefaultTrue,
"bionic": Bp2BuildDefaultTrueRecursively,
"bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue,
- "build/bazel/examples/apex/minimal": Bp2BuildDefaultTrueRecursively,
- "build/bazel/examples/soong_config_variables": Bp2BuildDefaultTrueRecursively,
- "build/make/target/product/security": Bp2BuildDefaultTrue,
- "build/make/tools/signapk": Bp2BuildDefaultTrue,
- "build/soong": Bp2BuildDefaultTrue,
- "build/soong/cc/libbuildversion": Bp2BuildDefaultTrue, // Skip tests subdir
- "build/soong/cc/ndkstubgen": Bp2BuildDefaultTrue,
- "build/soong/cc/symbolfile": Bp2BuildDefaultTrue,
- "build/soong/linkerconfig": Bp2BuildDefaultTrueRecursively,
- "build/soong/scripts": Bp2BuildDefaultTrueRecursively,
- "cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
- "development/apps/DevelopmentSettings": Bp2BuildDefaultTrue,
- "development/apps/Fallback": Bp2BuildDefaultTrue,
- "development/apps/WidgetPreview": Bp2BuildDefaultTrue,
- "development/samples/BasicGLSurfaceView": Bp2BuildDefaultTrue,
- "development/samples/BluetoothChat": Bp2BuildDefaultTrue,
- "development/samples/BrokenKeyDerivation": Bp2BuildDefaultTrue,
- "development/samples/Compass": Bp2BuildDefaultTrue,
- "development/samples/ContactManager": Bp2BuildDefaultTrue,
- "development/samples/FixedGridLayout": Bp2BuildDefaultTrue,
- "development/samples/HelloEffects": Bp2BuildDefaultTrue,
- "development/samples/Home": Bp2BuildDefaultTrue,
- "development/samples/HoneycombGallery": Bp2BuildDefaultTrue,
- "development/samples/JetBoy": Bp2BuildDefaultTrue,
- "development/samples/KeyChainDemo": Bp2BuildDefaultTrue,
- "development/samples/LceDemo": Bp2BuildDefaultTrue,
- "development/samples/LunarLander": Bp2BuildDefaultTrue,
- "development/samples/MultiResolution": Bp2BuildDefaultTrue,
- "development/samples/MultiWindow": Bp2BuildDefaultTrue,
- "development/samples/NotePad": Bp2BuildDefaultTrue,
- "development/samples/Obb": Bp2BuildDefaultTrue,
- "development/samples/RSSReader": Bp2BuildDefaultTrue,
- "development/samples/ReceiveShareDemo": Bp2BuildDefaultTrue,
- "development/samples/SearchableDictionary": Bp2BuildDefaultTrue,
- "development/samples/SipDemo": Bp2BuildDefaultTrue,
- "development/samples/SkeletonApp": Bp2BuildDefaultTrue,
- "development/samples/Snake": Bp2BuildDefaultTrue,
- "development/samples/SpellChecker/": Bp2BuildDefaultTrueRecursively,
- "development/samples/ThemedNavBarKeyboard": Bp2BuildDefaultTrue,
- "development/samples/ToyVpn": Bp2BuildDefaultTrue,
- "development/samples/TtsEngine": Bp2BuildDefaultTrue,
- "development/samples/USB/AdbTest": Bp2BuildDefaultTrue,
- "development/samples/USB/MissileLauncher": Bp2BuildDefaultTrue,
- "development/samples/VoiceRecognitionService": Bp2BuildDefaultTrue,
- "development/samples/VoicemailProviderDemo": Bp2BuildDefaultTrue,
- "development/samples/WiFiDirectDemo": Bp2BuildDefaultTrue,
- "development/sdk": Bp2BuildDefaultTrueRecursively,
- "external/aac": Bp2BuildDefaultTrueRecursively,
- "external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively,
- "external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
- "external/auto/common": Bp2BuildDefaultTrueRecursively,
- "external/auto/service": Bp2BuildDefaultTrueRecursively,
- "external/boringssl": Bp2BuildDefaultTrueRecursively,
- "external/bouncycastle": Bp2BuildDefaultTrue,
- "external/brotli": Bp2BuildDefaultTrue,
- "external/conscrypt": Bp2BuildDefaultTrue,
- "external/e2fsprogs": Bp2BuildDefaultTrueRecursively,
- "external/eigen": Bp2BuildDefaultTrueRecursively,
- "external/error_prone": Bp2BuildDefaultTrueRecursively,
- "external/flac": Bp2BuildDefaultTrueRecursively,
- "external/fmtlib": Bp2BuildDefaultTrueRecursively,
- "external/google-benchmark": Bp2BuildDefaultTrueRecursively,
- "external/googletest": Bp2BuildDefaultTrueRecursively,
- "external/gwp_asan": Bp2BuildDefaultTrueRecursively,
- "external/hamcrest": Bp2BuildDefaultTrueRecursively,
- "external/icu": Bp2BuildDefaultTrueRecursively,
- "external/icu/android_icu4j": Bp2BuildDefaultFalse, // java rules incomplete
- "external/icu/icu4j": Bp2BuildDefaultFalse, // java rules incomplete
- "external/jarjar": Bp2BuildDefaultTrueRecursively,
- "external/javapoet": Bp2BuildDefaultTrueRecursively,
- "external/jemalloc_new": Bp2BuildDefaultTrueRecursively,
- "external/jsoncpp": Bp2BuildDefaultTrueRecursively,
- "external/junit": Bp2BuildDefaultTrueRecursively,
- "external/libavc": Bp2BuildDefaultTrueRecursively,
- "external/libcap": Bp2BuildDefaultTrueRecursively,
- "external/libcxx": Bp2BuildDefaultTrueRecursively,
- "external/libcxxabi": Bp2BuildDefaultTrueRecursively,
- "external/libevent": Bp2BuildDefaultTrueRecursively,
- "external/libgav1": Bp2BuildDefaultTrueRecursively,
- "external/libhevc": Bp2BuildDefaultTrueRecursively,
- "external/libmpeg2": Bp2BuildDefaultTrueRecursively,
- "external/libpng": Bp2BuildDefaultTrueRecursively,
- "external/lz4/lib": Bp2BuildDefaultTrue,
- "external/lzma/C": Bp2BuildDefaultTrueRecursively,
- "external/mdnsresponder": Bp2BuildDefaultTrueRecursively,
- "external/minijail": Bp2BuildDefaultTrueRecursively,
- "external/pcre": Bp2BuildDefaultTrueRecursively,
- "external/protobuf": Bp2BuildDefaultTrueRecursively,
- "external/python/six": Bp2BuildDefaultTrueRecursively,
- "external/rappor": Bp2BuildDefaultTrueRecursively,
- "external/scudo": Bp2BuildDefaultTrueRecursively,
- "external/selinux/libselinux": Bp2BuildDefaultTrueRecursively,
- "external/selinux/libsepol": Bp2BuildDefaultTrueRecursively,
- "external/zlib": Bp2BuildDefaultTrueRecursively,
- "external/zstd": Bp2BuildDefaultTrueRecursively,
- "frameworks/av/media/codecs/g711/decoder": Bp2BuildDefaultTrueRecursively,
+
+ "build/bazel/examples/apex/minimal": Bp2BuildDefaultTrueRecursively,
+ "build/bazel/examples/soong_config_variables": Bp2BuildDefaultTrueRecursively,
+ "build/bazel/examples/python": Bp2BuildDefaultTrueRecursively,
+ "build/bazel/examples/gensrcs": Bp2BuildDefaultTrueRecursively,
+ "build/make/target/product/security": Bp2BuildDefaultTrue,
+ "build/make/tools/signapk": Bp2BuildDefaultTrue,
+ "build/make/tools/zipalign": Bp2BuildDefaultTrueRecursively,
+ "build/soong": Bp2BuildDefaultTrue,
+ "build/soong/cc/libbuildversion": Bp2BuildDefaultTrue, // Skip tests subdir
+ "build/soong/cc/ndkstubgen": Bp2BuildDefaultTrue,
+ "build/soong/cc/symbolfile": Bp2BuildDefaultTrue,
+ "build/soong/linkerconfig": Bp2BuildDefaultTrueRecursively,
+ "build/soong/scripts": Bp2BuildDefaultTrueRecursively,
+
+ "cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
+ "development/apps/DevelopmentSettings": Bp2BuildDefaultTrue,
+ "development/apps/Fallback": Bp2BuildDefaultTrue,
+ "development/apps/WidgetPreview": Bp2BuildDefaultTrue,
+ "development/samples/BasicGLSurfaceView": Bp2BuildDefaultTrue,
+ "development/samples/BluetoothChat": Bp2BuildDefaultTrue,
+ "development/samples/BrokenKeyDerivation": Bp2BuildDefaultTrue,
+ "development/samples/Compass": Bp2BuildDefaultTrue,
+ "development/samples/ContactManager": Bp2BuildDefaultTrue,
+ "development/samples/FixedGridLayout": Bp2BuildDefaultTrue,
+ "development/samples/HelloEffects": Bp2BuildDefaultTrue,
+ "development/samples/Home": Bp2BuildDefaultTrue,
+ "development/samples/HoneycombGallery": Bp2BuildDefaultTrue,
+ "development/samples/JetBoy": Bp2BuildDefaultTrue,
+ "development/samples/KeyChainDemo": Bp2BuildDefaultTrue,
+ "development/samples/LceDemo": Bp2BuildDefaultTrue,
+ "development/samples/LunarLander": Bp2BuildDefaultTrue,
+ "development/samples/MultiResolution": Bp2BuildDefaultTrue,
+ "development/samples/MultiWindow": Bp2BuildDefaultTrue,
+ "development/samples/NotePad": Bp2BuildDefaultTrue,
+ "development/samples/Obb": Bp2BuildDefaultTrue,
+ "development/samples/RSSReader": Bp2BuildDefaultTrue,
+ "development/samples/ReceiveShareDemo": Bp2BuildDefaultTrue,
+ "development/samples/SearchableDictionary": Bp2BuildDefaultTrue,
+ "development/samples/SipDemo": Bp2BuildDefaultTrue,
+ "development/samples/SkeletonApp": Bp2BuildDefaultTrue,
+ "development/samples/Snake": Bp2BuildDefaultTrue,
+ "development/samples/SpellChecker/": Bp2BuildDefaultTrueRecursively,
+ "development/samples/ThemedNavBarKeyboard": Bp2BuildDefaultTrue,
+ "development/samples/ToyVpn": Bp2BuildDefaultTrue,
+ "development/samples/TtsEngine": Bp2BuildDefaultTrue,
+ "development/samples/USB/AdbTest": Bp2BuildDefaultTrue,
+ "development/samples/USB/MissileLauncher": Bp2BuildDefaultTrue,
+ "development/samples/VoiceRecognitionService": Bp2BuildDefaultTrue,
+ "development/samples/VoicemailProviderDemo": Bp2BuildDefaultTrue,
+ "development/samples/WiFiDirectDemo": Bp2BuildDefaultTrue,
+ "development/sdk": Bp2BuildDefaultTrueRecursively,
+
+ "external/aac": Bp2BuildDefaultTrueRecursively,
+ "external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively,
+ "external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
+ "external/auto/common": Bp2BuildDefaultTrueRecursively,
+ "external/auto/service": Bp2BuildDefaultTrueRecursively,
+ "external/boringssl": Bp2BuildDefaultTrueRecursively,
+ "external/bouncycastle": Bp2BuildDefaultTrue,
+ "external/brotli": Bp2BuildDefaultTrue,
+ "external/conscrypt": Bp2BuildDefaultTrue,
+ "external/e2fsprogs": Bp2BuildDefaultTrueRecursively,
+ "external/eigen": Bp2BuildDefaultTrueRecursively,
+ "external/erofs-utils": Bp2BuildDefaultTrueRecursively,
+ "external/error_prone": Bp2BuildDefaultTrueRecursively,
+ "external/expat": Bp2BuildDefaultTrueRecursively,
+ "external/f2fs-tools": Bp2BuildDefaultTrue,
+ "external/flac": Bp2BuildDefaultTrueRecursively,
+ "external/fmtlib": Bp2BuildDefaultTrueRecursively,
+ "external/google-benchmark": Bp2BuildDefaultTrueRecursively,
+ "external/googletest": Bp2BuildDefaultTrueRecursively,
+ "external/gwp_asan": Bp2BuildDefaultTrueRecursively,
+ "external/hamcrest": Bp2BuildDefaultTrueRecursively,
+ "external/icu": Bp2BuildDefaultTrueRecursively,
+ "external/icu/android_icu4j": Bp2BuildDefaultFalse, // java rules incomplete
+ "external/icu/icu4j": Bp2BuildDefaultFalse, // java rules incomplete
+ "external/jarjar": Bp2BuildDefaultTrueRecursively,
+ "external/javapoet": Bp2BuildDefaultTrueRecursively,
+ "external/jemalloc_new": Bp2BuildDefaultTrueRecursively,
+ "external/jsoncpp": Bp2BuildDefaultTrueRecursively,
+ "external/junit": Bp2BuildDefaultTrueRecursively,
+ "external/libavc": Bp2BuildDefaultTrueRecursively,
+ "external/libcap": Bp2BuildDefaultTrueRecursively,
+ "external/libcxx": Bp2BuildDefaultTrueRecursively,
+ "external/libcxxabi": Bp2BuildDefaultTrueRecursively,
+ "external/libevent": Bp2BuildDefaultTrueRecursively,
+ "external/libgav1": Bp2BuildDefaultTrueRecursively,
+ "external/libhevc": Bp2BuildDefaultTrueRecursively,
+ "external/libjpeg-turbo": Bp2BuildDefaultTrueRecursively,
+ "external/libmpeg2": Bp2BuildDefaultTrueRecursively,
+ "external/libpng": Bp2BuildDefaultTrueRecursively,
+ "external/lz4/lib": Bp2BuildDefaultTrue,
+ "external/lzma/C": Bp2BuildDefaultTrueRecursively,
+ "external/mdnsresponder": Bp2BuildDefaultTrueRecursively,
+ "external/minijail": Bp2BuildDefaultTrueRecursively,
+ "external/pcre": Bp2BuildDefaultTrueRecursively,
+ "external/protobuf": Bp2BuildDefaultTrueRecursively,
+ "external/python/six": Bp2BuildDefaultTrueRecursively,
+ "external/rappor": Bp2BuildDefaultTrueRecursively,
+ "external/scudo": Bp2BuildDefaultTrueRecursively,
+ "external/selinux/libselinux": Bp2BuildDefaultTrueRecursively,
+ "external/selinux/libsepol": Bp2BuildDefaultTrueRecursively,
+ "external/toybox": Bp2BuildDefaultTrueRecursively,
+ "external/zlib": Bp2BuildDefaultTrueRecursively,
+ "external/zopfli": Bp2BuildDefaultTrueRecursively,
+ "external/zstd": Bp2BuildDefaultTrueRecursively,
+
+ "frameworks/av/media/codecs": Bp2BuildDefaultTrueRecursively,
"frameworks/av/services/minijail": Bp2BuildDefaultTrueRecursively,
"frameworks/base/media/tests/MediaDump": Bp2BuildDefaultTrue,
"frameworks/base/startop/apps/test": Bp2BuildDefaultTrue,
@@ -154,56 +168,73 @@
"frameworks/native/opengl/tests/testPauseResume": Bp2BuildDefaultTrue,
"frameworks/native/opengl/tests/testViewport": Bp2BuildDefaultTrue,
"frameworks/proto_logging/stats/stats_log_api_gen": Bp2BuildDefaultTrueRecursively,
- "libnativehelper": Bp2BuildDefaultTrueRecursively,
- "packages/apps/DevCamera": Bp2BuildDefaultTrue,
- "packages/apps/HTMLViewer": Bp2BuildDefaultTrue,
- "packages/apps/Protips": Bp2BuildDefaultTrue,
- "packages/modules/StatsD/lib/libstatssocket": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb": Bp2BuildDefaultTrue,
- "packages/modules/adb/apex": Bp2BuildDefaultTrue,
- "packages/modules/adb/crypto": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb/libs": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb/pairing_auth": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb/pairing_connection": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb/proto": Bp2BuildDefaultTrueRecursively,
- "packages/modules/adb/tls": Bp2BuildDefaultTrueRecursively,
- "packages/providers/MediaProvider/tools/dialogs": Bp2BuildDefaultTrue,
- "packages/screensavers/Basic": Bp2BuildDefaultTrue,
- "packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultTrue,
- "prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
- "prebuilts/tools/common/m2": Bp2BuildDefaultTrue,
- "system/apex": Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
- "system/apex/libs": Bp2BuildDefaultTrueRecursively,
- "system/apex/proto": Bp2BuildDefaultTrueRecursively,
- "system/core/debuggerd": Bp2BuildDefaultTrueRecursively,
- "system/core/diagnose_usb": Bp2BuildDefaultTrueRecursively,
- "system/core/libasyncio": Bp2BuildDefaultTrue,
- "system/core/libcrypto_utils": Bp2BuildDefaultTrueRecursively,
- "system/core/libcutils": Bp2BuildDefaultTrueRecursively,
- "system/core/libpackagelistparser": Bp2BuildDefaultTrueRecursively,
- "system/core/libprocessgroup": Bp2BuildDefaultTrue,
- "system/core/libprocessgroup/cgrouprc": Bp2BuildDefaultTrue,
- "system/core/libprocessgroup/cgrouprc_format": Bp2BuildDefaultTrue,
- "system/core/libsystem": Bp2BuildDefaultTrueRecursively,
- "system/core/libutils": Bp2BuildDefaultTrueRecursively,
- "system/core/libvndksupport": Bp2BuildDefaultTrueRecursively,
- "system/core/property_service/libpropertyinfoparser": Bp2BuildDefaultTrueRecursively,
- "system/libartpalette": Bp2BuildDefaultTrueRecursively,
- "system/libbase": Bp2BuildDefaultTrueRecursively,
- "system/libfmq": Bp2BuildDefaultTrue,
- "system/libhwbinder": Bp2BuildDefaultTrueRecursively,
- "system/libprocinfo": Bp2BuildDefaultTrue,
- "system/libziparchive": Bp2BuildDefaultTrueRecursively,
- "system/logging/liblog": Bp2BuildDefaultTrueRecursively,
- "system/media/audio": Bp2BuildDefaultTrueRecursively,
- "system/memory/libmemunreachable": Bp2BuildDefaultTrueRecursively,
- "system/sepolicy/apex": Bp2BuildDefaultTrueRecursively,
- "system/timezone/apex": Bp2BuildDefaultTrueRecursively,
- "system/timezone/output_data": Bp2BuildDefaultTrueRecursively,
- "system/unwinding/libbacktrace": Bp2BuildDefaultTrueRecursively,
- "system/unwinding/libunwindstack": Bp2BuildDefaultTrueRecursively,
- "tools/apksig": Bp2BuildDefaultTrue,
- "tools/platform-compat/java/android/compat": Bp2BuildDefaultTrueRecursively,
+
+ "libnativehelper": Bp2BuildDefaultTrueRecursively,
+ "packages/apps/DevCamera": Bp2BuildDefaultTrue,
+ "packages/apps/HTMLViewer": Bp2BuildDefaultTrue,
+ "packages/apps/Protips": Bp2BuildDefaultTrue,
+ "packages/apps/WallpaperPicker": Bp2BuildDefaultTrue,
+ "packages/modules/StatsD/lib/libstatssocket": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb": Bp2BuildDefaultTrue,
+ "packages/modules/adb/apex": Bp2BuildDefaultTrue,
+ "packages/modules/adb/crypto": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb/libs": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb/pairing_auth": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb/pairing_connection": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb/proto": Bp2BuildDefaultTrueRecursively,
+ "packages/modules/adb/tls": Bp2BuildDefaultTrueRecursively,
+ "packages/providers/MediaProvider/tools/dialogs": Bp2BuildDefaultTrue,
+ "packages/screensavers/Basic": Bp2BuildDefaultTrue,
+ "packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultTrue,
+
+ "prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
+ "prebuilts/runtime/mainline/platform/sdk": Bp2BuildDefaultTrueRecursively,
+ "prebuilts/sdk/current/extras/app-toolkit": Bp2BuildDefaultTrue,
+ "prebuilts/sdk/current/support": Bp2BuildDefaultTrue,
+ "prebuilts/tools/common/m2": Bp2BuildDefaultTrue,
+
+ "system/apex": Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
+ "system/apex/apexer": Bp2BuildDefaultTrue,
+ "system/apex/libs": Bp2BuildDefaultTrueRecursively,
+ "system/apex/proto": Bp2BuildDefaultTrueRecursively,
+ "system/apex/tools": Bp2BuildDefaultTrueRecursively,
+ "system/core/debuggerd": Bp2BuildDefaultTrueRecursively,
+ "system/core/diagnose_usb": Bp2BuildDefaultTrueRecursively,
+ "system/core/libasyncio": Bp2BuildDefaultTrue,
+ "system/core/libcrypto_utils": Bp2BuildDefaultTrueRecursively,
+ "system/core/libcutils": Bp2BuildDefaultTrueRecursively,
+ "system/core/libpackagelistparser": Bp2BuildDefaultTrueRecursively,
+ "system/core/libprocessgroup": Bp2BuildDefaultTrue,
+ "system/core/libprocessgroup/cgrouprc": Bp2BuildDefaultTrue,
+ "system/core/libprocessgroup/cgrouprc_format": Bp2BuildDefaultTrue,
+ "system/core/libsystem": Bp2BuildDefaultTrueRecursively,
+ "system/core/libutils": Bp2BuildDefaultTrueRecursively,
+ "system/core/libvndksupport": Bp2BuildDefaultTrueRecursively,
+ "system/core/property_service/libpropertyinfoparser": Bp2BuildDefaultTrueRecursively,
+ "system/core/property_service/libpropertyinfoserializer": Bp2BuildDefaultTrueRecursively,
+ "system/libartpalette": Bp2BuildDefaultTrueRecursively,
+ "system/libbase": Bp2BuildDefaultTrueRecursively,
+ "system/libfmq": Bp2BuildDefaultTrue,
+ "system/libhidl/transport/base/1.0": Bp2BuildDefaultTrue,
+ "system/libhidl/transport/manager/1.0": Bp2BuildDefaultTrue,
+ "system/libhidl/transport/manager/1.1": Bp2BuildDefaultTrue,
+ "system/libhidl/transport/manager/1.2": Bp2BuildDefaultTrue,
+ "system/libhwbinder": Bp2BuildDefaultTrueRecursively,
+ "system/libprocinfo": Bp2BuildDefaultTrue,
+ "system/libziparchive": Bp2BuildDefaultTrueRecursively,
+ "system/logging/liblog": Bp2BuildDefaultTrueRecursively,
+ "system/media/audio": Bp2BuildDefaultTrueRecursively,
+ "system/memory/libion": Bp2BuildDefaultTrueRecursively,
+ "system/memory/libmemunreachable": Bp2BuildDefaultTrueRecursively,
+ "system/sepolicy/apex": Bp2BuildDefaultTrueRecursively,
+ "system/timezone/apex": Bp2BuildDefaultTrueRecursively,
+ "system/timezone/output_data": Bp2BuildDefaultTrueRecursively,
+ "system/tools/sysprop": Bp2BuildDefaultTrue,
+ "system/unwinding/libunwindstack": Bp2BuildDefaultTrueRecursively,
+
+ "tools/apksig": Bp2BuildDefaultTrue,
+ "tools/platform-compat/java/android/compat": Bp2BuildDefaultTrueRecursively,
+ "tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively,
}
Bp2buildKeepExistingBuildFile = map[string]bool{
@@ -217,18 +248,21 @@
"build/bazel/ci/dist":/* recursive = */ false,
"build/bazel/examples/android_app":/* recursive = */ true,
"build/bazel/examples/java":/* recursive = */ true,
+ "build/bazel/examples/partitions":/* recursive = */ true,
"build/bazel/bazel_skylib":/* recursive = */ true,
"build/bazel/rules":/* recursive = */ true,
"build/bazel/rules_cc":/* recursive = */ true,
"build/bazel/scripts":/* recursive = */ true,
"build/bazel/tests":/* recursive = */ true,
"build/bazel/platforms":/* recursive = */ true,
+ "build/bazel/product_config":/* recursive = */ true,
"build/bazel/product_variables":/* recursive = */ true,
"build/bazel/vendor/google":/* recursive = */ true,
"build/bazel_common_rules":/* recursive = */ true,
// build/make/tools/signapk BUILD file is generated, so build/make/tools is not recursive.
"build/make/tools":/* recursive = */ false,
"build/pesto":/* recursive = */ true,
+ "build/soong/ui/metrics/bp2build_progress_metrics_proto":/* recursive = */ true,
// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
// e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed
@@ -240,36 +274,87 @@
"packages/apps/Music":/* recursive = */ true,
"packages/apps/QuickSearchBox":/* recursive = */ true,
- "packages/apps/WallpaperPicker":/* recursive = */ false,
+ "prebuilts/bazel":/* recursive = */ true,
"prebuilts/bundletool":/* recursive = */ true,
"prebuilts/gcc":/* recursive = */ true,
"prebuilts/build-tools":/* recursive = */ true,
"prebuilts/jdk/jdk11":/* recursive = */ false,
+ "prebuilts/misc":/* recursive = */ false, // not recursive because we need bp2build converted build files in prebuilts/misc/common/asm
"prebuilts/sdk":/* recursive = */ false,
- "prebuilts/sdk/current/extras/app-toolkit":/* recursive = */ false,
- "prebuilts/sdk/current/support":/* recursive = */ false,
"prebuilts/sdk/tools":/* recursive = */ false,
"prebuilts/r8":/* recursive = */ false,
}
Bp2buildModuleAlwaysConvertList = []string{
// cc mainline modules
- "libnativeloader-headers",
- "libgui_bufferqueue_sources",
"code_coverage.policy",
"code_coverage.policy.other",
"codec2_soft_exports",
+ "com.android.media.swcodec-androidManifest",
"com.android.media.swcodec-ld.config.txt",
- "libcodec2_headers",
- "libcodec2_internal",
"com.android.media.swcodec-mediaswcodec.rc",
+ "com.android.media.swcodec.certificate",
+ "com.android.media.swcodec.key",
+ "com.android.neuralnetworks-androidManifest",
+ "com.android.neuralnetworks.certificate",
+ "com.android.neuralnetworks.key",
"flatbuffer_headers",
"gemmlowp_headers",
"gl_headers",
- "libbluetooth-types-header",
+ "libandroid_runtime_lazy",
+ "libandroid_runtime_vm_headers",
"libaudioclient_aidl_conversion_util",
"libaudioutils_fixedfft",
+ "libbinder_headers",
+ "libbinder_headers_platform_shared",
+ "libbluetooth-types-header",
+ "libbufferhub_headers",
+ "libcodec2",
+ "libcodec2_headers",
+ "libcodec2_internal",
+ "libdmabufheap",
+ "libdvr_headers",
+ "libgsm",
+ "libgui_bufferqueue_sources",
+ "libhardware",
+ "libhardware_headers",
+ "libincfs_headers",
+ "libnativeloader-headers",
+ "libnativewindow_headers",
+ "libneuralnetworks_headers",
+ "libopus",
+ "libpdx_headers",
+ "libprocpartition",
+ "libruy_static",
+ "libserviceutils",
+ "libstagefright_enc_common",
+ "libstagefright_foundation_headers",
+ "libstagefright_headers",
+ "libsurfaceflinger_headers",
+ "libsync",
+ "libtextclassifier_hash_headers",
+ "libtextclassifier_hash_static",
+ "libtflite_kernel_utils",
+ "libtinyxml2",
+ "libui-types",
+ "libui_headers",
+ "libvorbisidec",
+ "media_ndk_headers",
+ "media_plugin_headers",
+ "mediaswcodec.policy",
+ "mediaswcodec.xml",
+ "philox_random",
+ "philox_random_headers",
+ "server_configurable_flags",
+ "tensorflow_headers",
+
+ // fastboot
+ "bootimg_headers",
+ "fastboot",
+ "libfastboot",
+ "liblp",
+ "libstorage_literals_headers",
//external/avb
"avbtool",
@@ -284,6 +369,7 @@
//system/extras/ext4_utils
"libext4_utils",
+ "mke2fs_conf",
//system/extras/libfec
"libfec",
@@ -301,31 +387,40 @@
"car-ui-androidx-core-common-nodeps",
"car-ui-androidx-lifecycle-common-nodeps",
"car-ui-androidx-constraintlayout-solver-nodeps",
+
+ //system/libhidl
+ // needed by cc_hidl_library
+ "libhidlbase",
}
Bp2buildModuleTypeAlwaysConvertList = []string{
+ "linker_config",
"java_import",
"java_import_host",
}
Bp2buildModuleDoNotConvertList = []string{
// cc bugs
- "libsepol", // TODO(b/207408632): Unsupported case of .l sources in cc library rules
"libactivitymanager_aidl", // TODO(b/207426160): Unsupported use of aidl sources (via Dactivity_manager_procstate_aidl) in a cc_library
"gen-kotlin-build-file.py", // TODO(b/198619163) module has same name as source
"libgtest_ndk_c++", "libgtest_main_ndk_c++", // TODO(b/201816222): Requires sdk_version support.
"linkerconfig", "mdnsd", // TODO(b/202876379): has arch-variant static_executable
- "linker", // TODO(b/228316882): cc_binary uses link_crt
- "libdebuggerd", // TODO(b/228314770): support product variable-specific header_libs
- "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
+ "linker", // TODO(b/228316882): cc_binary uses link_crt
+ "libdebuggerd", // TODO(b/228314770): support product variable-specific header_libs
+ "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
+ "libspeexresampler", // TODO(b/231995978): Filter out unknown cflags
+ "libvpx", // TODO(b/240756936): Arm neon variant not supported
+ "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
// java bugs
"libbase_ndk", // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
// python protos
- "libprotobuf-python", // TODO(b/196084681): contains .proto sources
- "apex_build_info_proto", "apex_manifest_proto", // TODO(b/196084681): a python lib with proto sources
- "linker_config_proto", // TODO(b/196084681): contains .proto sources
+ "libprotobuf-python", // Has a handcrafted alternative
// genrule incompatibilities
"brotli-fuzzer-corpus", // TODO(b/202015218): outputs are in location incompatible with bazel genrule handling.
@@ -336,6 +431,9 @@
"prebuilt_platform-robolectric-4.4-prebuilt", // aosp/1999250, needs .aar support in Jars
"prebuilt_platform-robolectric-4.5.1-prebuilt", // aosp/1999250, needs .aar support in Jars
+ // proto support
+ "libstats_proto_host", // TODO(b/236055697): handle protos from other packages
+
// path property for filegroups
"conscrypt", // TODO(b/210751803), we don't handle path property for filegroups
"conscrypt-for-host", // TODO(b/210751803), we don't handle path property for filegroups
@@ -363,26 +461,27 @@
"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
- "abb", // depends on unconverted modules: libcmd, libbinder
- "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_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
- "chkcon", "sefcontext_compile", // depends on unconverted modules: libsepol
+ "CarHTMLViewer", // depends on unconverted modules android.car-stubs, car-ui-lib
+ "abb", // depends on unconverted modules: libcmd, libbinder
+ "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_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
"com.android.runtime", // depends on unconverted modules: bionic-linker-config, linkerconfig
- "conv_linker_config", // depends on unconverted modules: linker_config_proto
"currysrc", // depends on unconverted modules: currysrc_org.eclipse, guavalib, jopt-simple-4.9
"dex2oat-script", // depends on unconverted modules: dex2oat
"generated_android_icu4j_resources", // depends on unconverted modules: android_icu4j_srcgen_binary, soong_zip
"generated_android_icu4j_test_resources", // depends on unconverted modules: android_icu4j_srcgen_binary, soong_zip
"host-libprotobuf-java-nano", // b/220869005, depends on libprotobuf-java-nano
"libadb_host", // depends on unconverted modules: AdbWinApi, libopenscreen-discovery, libopenscreen-platform-impl, libusb
+ "libapexutil", // depends on unconverted modules: apex-info-list-tinyxml
"libart", // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support
"libart-runtime-gtest", // depends on unconverted modules: libgtest_isolated, libart-compiler, libdexfile, libprofile, libartbase, libartbase-art-gtest
"libart_headers", // depends on unconverted modules: art_libartbase_headers
+ "libartbase-art-gtest", // depends on unconverted modules: libgtest_isolated, libart, libart-compiler, libdexfile, libprofile
+ "libartbased-art-gtest", // depends on unconverted modules: libgtest_isolated, libartd, libartd-compiler, libdexfiled, libprofiled
"libartd", // depends on unconverted modules: art_operator_srcs, libcpu_features, libodrstatslog, libelffiled, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfiled, libnativebridge, libnativeloader, libsigchain, libartbased, libprofiled, cpp-define-generator-asm-support, apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api
"libartd-runtime-gtest", // depends on unconverted modules: libgtest_isolated, libartd-compiler, libdexfiled, libprofiled, libartbased, libartbased-art-gtest
"libdebuggerd_handler", // depends on unconverted module libdebuggerd_handler_core
@@ -405,6 +504,7 @@
"stats-log-api-gen", // depends on unconverted modules: libstats_proto_host
"statslog.cpp", "statslog.h", "statslog.rs", // depends on unconverted modules: stats-log-api-gen
"statslog_art.cpp", "statslog_art.h", "statslog_header.rs", // depends on unconverted modules: stats-log-api-gen
+ "test_fips", // depends on unconverted modules: adb
"timezone-host", // depends on unconverted modules: art.module.api.annotations
"truth-host-prebuilt", // depends on unconverted modules: truth-prebuilt
"truth-prebuilt", // depends on unconverted modules: asm-7.0, guava
@@ -412,11 +512,16 @@
// b/215723302; awaiting tz{data,_version} to then rename targets conflicting with srcs
"tzdata",
"tz_version",
+
+ // '//bionic/libc:libc_bp2build_cc_library_static' is duplicated in the 'deps' attribute of rule
+ "toybox-static",
}
Bp2buildCcLibraryStaticOnlyList = []string{}
MixedBuildsDisabledList = []string{
+ "libruy_static", "libtflite_kernel_utils", // TODO(b/237315968); Depend on prebuilt stl, not from source
+
"art_libdexfile_dex_instruction_list_header", // breaks libart_mterp.armng, header not found
"libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy
@@ -455,5 +560,20 @@
"simpleperf_ndk",
"toybox-static",
"zlib_bench",
+
+ // java_import[_host] issues
+ // tradefed prebuilts depend on libprotobuf
+ "prebuilt_tradefed",
+ "prebuilt_tradefed-test-framework",
+ // handcrafted BUILD.bazel files in //prebuilts/...
+ "prebuilt_r8lib-prebuilt",
+ "prebuilt_sdk-core-lambda-stubs",
+ "prebuilt_android-support-collections-nodeps",
+ "prebuilt_android-arch-core-common-nodeps",
+ "prebuilt_android-arch-lifecycle-common-java8-nodeps",
+ "prebuilt_android-arch-lifecycle-common-nodeps",
+ "prebuilt_android-support-annotations-nodeps",
+ "prebuilt_android-arch-paging-common-nodeps",
+ "prebuilt_android-arch-room-common-nodeps",
}
)
diff --git a/android/androidmk.go b/android/androidmk.go
index 5c715b4..006e43d 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -288,6 +288,8 @@
// The contributions to the dist.
type distContributions struct {
+ // Path to license metadata file.
+ licenseMetadataFile Path
// List of goals and the dist copy instructions.
copiesForGoals []*copiesForGoals
}
@@ -364,6 +366,8 @@
// Collate the contributions this module makes to the dist.
distContributions := &distContributions{}
+ distContributions.licenseMetadataFile = amod.licenseMetadataFile
+
// Iterate over this module's dist structs, merged from the dist and dists properties.
for _, dist := range amod.Dists() {
// Get the list of goals this dist should be enabled for. e.g. sdk, droidcore
@@ -456,6 +460,10 @@
for _, c := range d.copies {
ret = append(
ret,
+ fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))\n",
+ c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String()))
+ ret = append(
+ ret,
fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", d.goals, c.from.String(), c.dest))
}
}
@@ -596,10 +604,6 @@
}
}
- if len(base.noticeFiles) > 0 {
- a.SetString("LOCAL_NOTICE_FILE", strings.Join(base.noticeFiles.Strings(), " "))
- }
-
if host {
makeOs := base.Os().String()
if base.Os() == Linux || base.Os() == LinuxBionic || base.Os() == LinuxMusl {
@@ -937,7 +941,10 @@
return !module.Enabled() ||
module.commonProperties.HideFromMake ||
// Make does not understand LinuxBionic
- module.Os() == LinuxBionic
+ module.Os() == LinuxBionic ||
+ // Make does not understand LinuxMusl, except when we are building with USE_HOST_MUSL=true
+ // and all host binaries are LinuxMusl
+ (module.Os() == LinuxMusl && module.Target().HostCross)
}
// A utility func to format LOCAL_TEST_DATA outputs. See the comments on DataPath to understand how
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
index caf11f1..ae2187f 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -50,6 +50,8 @@
func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ m.base().licenseMetadataFile = PathForOutput(ctx, "meta_lic")
+
// If the dist_output_file: true then create an output file that is stored in
// the OutputFile property of the AndroidMkEntry.
if proptools.BoolDefault(m.properties.Dist_output_file, true) {
@@ -198,10 +200,13 @@
},
}
+ dc.licenseMetadataFile = PathForTesting("meta_lic")
makeOutput := generateDistContributionsForMake(dc)
assertStringEquals(t, `.PHONY: my_goal
+$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))
$(call dist-for-goals,my_goal,one.out:one.out)
+$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))
$(call dist-for-goals,my_goal,two.out:other.out)
`, strings.Join(makeOutput, ""))
}
@@ -243,18 +248,26 @@
expectedAndroidMkLines := []string{
".PHONY: my_second_goal\n",
+ "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_second_goal,two.out:two.out)\n",
+ "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n",
".PHONY: my_third_goal\n",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n",
".PHONY: my_fourth_goal\n",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n",
".PHONY: my_fifth_goal\n",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n",
".PHONY: my_sixth_goal\n",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n",
".PHONY: my_goal my_other_goal\n",
+ "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n",
+ "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n",
}
@@ -274,7 +287,7 @@
)
}
for idx, line := range androidMkLines {
- expectedLine := expectedAndroidMkLines[idx]
+ expectedLine := strings.ReplaceAll(expectedAndroidMkLines[idx], "meta_lic", module.base().licenseMetadataFile.String())
if line != expectedLine {
t.Errorf(
"Expected AndroidMk line to be '%s', got '%s'",
diff --git a/android/apex.go b/android/apex.go
index 019efdd..934cf72 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -454,6 +454,7 @@
}
return InList(what, apex_available) ||
(what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) ||
+ (what == "com.android.btservices" && InList("com.android.bluetooth", apex_available)) ||
(strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available))
}
@@ -836,40 +837,6 @@
ctx.Phony(fmt.Sprintf("%s-depsinfo", ctx.ModuleName()), d.fullListPath, d.flatListPath)
}
-// TODO(b/158059172): remove minSdkVersion allowlist
-var minSdkVersionAllowlist = func(apiMap map[string]int) map[string]ApiLevel {
- list := make(map[string]ApiLevel, len(apiMap))
- for name, finalApiInt := range apiMap {
- list[name] = uncheckedFinalApiLevel(finalApiInt)
- }
- return list
-}(map[string]int{
- "androidx-constraintlayout_constraintlayout-solver-nodeps": 29,
- "apache-commons-compress": 29,
- "bouncycastle_ike_digests": 30,
- "brotli-java": 29,
- "flatbuffer_headers": 30,
- "gemmlowp_headers": 30,
- "ike-internals": 30,
- "libbrotli": 30,
- "libcrypto_static": 30,
- "libeigen": 30,
- "liblz4": 30,
- "libmdnssd": 30,
- "libprocpartition": 30,
- "libprotobuf-java-lite": 30,
- "libprotoutil": 30,
- "libtextclassifier_hash_headers": 30,
- "libtextclassifier_hash_static": 30,
- "libtflite_kernel_utils": 30,
- "libzstd": 30,
- "net-utils-framework-common": 29,
- "philox_random_headers": 30,
- "philox_random": 30,
- "tensorflow_headers": 30,
- "xz-java": 29,
-})
-
// Function called while walking an APEX's payload dependencies.
//
// Return true if the `to` module should be visited, false otherwise.
@@ -921,15 +888,13 @@
}
if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil {
toName := ctx.OtherModuleName(to)
- if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver.GreaterThan(minSdkVersion) {
- ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v."+
- "\n\nDependency path: %s\n\n"+
- "Consider adding 'min_sdk_version: %q' to %q",
- minSdkVersion, ctx.ModuleName(), err.Error(),
- ctx.GetPathString(false),
- minSdkVersion, toName)
- return false
- }
+ ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v."+
+ "\n\nDependency path: %s\n\n"+
+ "Consider adding 'min_sdk_version: %q' to %q",
+ minSdkVersion, ctx.ModuleName(), err.Error(),
+ ctx.GetPathString(false),
+ minSdkVersion, toName)
+ return false
}
return true
})
diff --git a/android/api_levels.go b/android/api_levels.go
index 8163894..bf7b317 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -54,6 +54,14 @@
isPreview bool
}
+func (this ApiLevel) FinalInt() int {
+ if this.IsPreview() {
+ panic("Requested a final int from a non-final ApiLevel")
+ } else {
+ return this.number
+ }
+}
+
func (this ApiLevel) FinalOrFutureInt() int {
if this.IsPreview() {
return FutureApiLevelInt
@@ -184,17 +192,9 @@
// a core-for-system-modules.jar for the module-lib API scope.
var LastWithoutModuleLibCoreSystemModules = uncheckedFinalApiLevel(31)
-// If the `raw` input is the codename of an API level has been finalized, this
-// function returns the API level number associated with that API level. If the
-// input is *not* a finalized codename, the input is returned unmodified.
-//
-// For example, at the time of writing, R has been finalized as API level 30,
-// but S is in development so it has no number assigned. For the following
-// inputs:
-//
-// * "30" -> "30"
-// * "R" -> "30"
-// * "S" -> "S"
+// ReplaceFinalizedCodenames returns the API level number associated with that API level
+// if the `raw` input is the codename of an API level has been finalized.
+// If the input is *not* a finalized codename, the input is returned unmodified.
func ReplaceFinalizedCodenames(config Config, raw string) string {
num, ok := getFinalCodenamesMap(config)[raw]
if !ok {
@@ -307,24 +307,25 @@
func getFinalCodenamesMap(config Config) map[string]int {
return config.Once(finalCodenamesMapKey, func() interface{} {
apiLevelsMap := map[string]int{
- "G": 9,
- "I": 14,
- "J": 16,
- "J-MR1": 17,
- "J-MR2": 18,
- "K": 19,
- "L": 21,
- "L-MR1": 22,
- "M": 23,
- "N": 24,
- "N-MR1": 25,
- "O": 26,
- "O-MR1": 27,
- "P": 28,
- "Q": 29,
- "R": 30,
- "S": 31,
- "S-V2": 32,
+ "G": 9,
+ "I": 14,
+ "J": 16,
+ "J-MR1": 17,
+ "J-MR2": 18,
+ "K": 19,
+ "L": 21,
+ "L-MR1": 22,
+ "M": 23,
+ "N": 24,
+ "N-MR1": 25,
+ "O": 26,
+ "O-MR1": 27,
+ "P": 28,
+ "Q": 29,
+ "R": 30,
+ "S": 31,
+ "S-V2": 32,
+ "Tiramisu": 33,
}
// TODO: Differentiate "current" and "future".
@@ -351,24 +352,25 @@
func GetApiLevelsMap(config Config) map[string]int {
return config.Once(apiLevelsMapKey, func() interface{} {
apiLevelsMap := map[string]int{
- "G": 9,
- "I": 14,
- "J": 16,
- "J-MR1": 17,
- "J-MR2": 18,
- "K": 19,
- "L": 21,
- "L-MR1": 22,
- "M": 23,
- "N": 24,
- "N-MR1": 25,
- "O": 26,
- "O-MR1": 27,
- "P": 28,
- "Q": 29,
- "R": 30,
- "S": 31,
- "S-V2": 32,
+ "G": 9,
+ "I": 14,
+ "J": 16,
+ "J-MR1": 17,
+ "J-MR2": 18,
+ "K": 19,
+ "L": 21,
+ "L-MR1": 22,
+ "M": 23,
+ "N": 24,
+ "N-MR1": 25,
+ "O": 26,
+ "O-MR1": 27,
+ "P": 28,
+ "Q": 29,
+ "R": 30,
+ "S": 31,
+ "S-V2": 32,
+ "Tiramisu": 33,
}
for i, codename := range config.PlatformVersionActiveCodenames() {
apiLevelsMap[codename] = previewAPILevelBase + i
diff --git a/android/arch.go b/android/arch.go
index f732a7d..b5bd2f0 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -307,7 +307,7 @@
// Linux is the OS for the Linux kernel plus the glibc runtime.
Linux = newOsType("linux_glibc", Host, false, X86, X86_64)
// LinuxMusl is the OS for the Linux kernel plus the musl runtime.
- LinuxMusl = newOsType("linux_musl", Host, false, X86, X86_64)
+ LinuxMusl = newOsType("linux_musl", Host, false, X86, X86_64, Arm64, Arm)
// Darwin is the OS for MacOS/Darwin host machines.
Darwin = newOsType("darwin", Host, false, Arm64, X86_64)
// LinuxBionic is the OS for the Linux kernel plus the Bionic libc runtime, but without the
@@ -393,54 +393,6 @@
}
}
-func registerBp2buildArchPathDepsMutator(ctx RegisterMutatorsContext) {
- ctx.BottomUp("bp2build-arch-pathdeps", bp2buildArchPathDepsMutator).Parallel()
-}
-
-// add dependencies for architecture specific properties tagged with `android:"path"`
-func bp2buildArchPathDepsMutator(ctx BottomUpMutatorContext) {
- var module Module
- module = ctx.Module()
-
- m := module.base()
- if !m.ArchSpecific() {
- return
- }
-
- // addPathDepsForProps does not descend into sub structs, so we need to descend into the
- // arch-specific properties ourselves
- var properties []interface{}
- for _, archProperties := range m.archProperties {
- for _, archProps := range archProperties {
- archPropValues := reflect.ValueOf(archProps).Elem()
- // there are three "arch" variations, descend into each
- for _, variant := range []string{"Arch", "Multilib", "Target"} {
- // The properties are an interface, get the value (a pointer) that it points to
- archProps := archPropValues.FieldByName(variant).Elem()
- if archProps.IsNil() {
- continue
- }
- // And then a pointer to a struct
- archProps = archProps.Elem()
- for i := 0; i < archProps.NumField(); i += 1 {
- f := archProps.Field(i)
- // If the value of the field is a struct (as opposed to a pointer to a struct) then step
- // into the BlueprintEmbed field.
- if f.Kind() == reflect.Struct {
- f = f.FieldByName("BlueprintEmbed")
- }
- if f.IsZero() {
- continue
- }
- props := f.Interface().(interface{})
- properties = append(properties, props)
- }
- }
- }
- }
- addPathDepsForProps(ctx, properties)
-}
-
// osMutator splits an arch-specific module into a variant for each OS that is enabled for the
// module. It uses the HostOrDevice value passed to InitAndroidArchModule and the
// device_supported and host_supported properties to determine which OsTypes are enabled for this
@@ -655,7 +607,8 @@
prefer32 := os == Windows
// Determine the multilib selection for this module.
- multilib, extraMultilib := decodeMultilib(base, os)
+ ignorePrefer32OnDevice := mctx.Config().IgnorePrefer32OnDevice()
+ multilib, extraMultilib := decodeMultilib(base, os, ignorePrefer32OnDevice)
// Convert the multilib selection into a list of Targets.
targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
@@ -730,7 +683,7 @@
// multilib from the factory's call to InitAndroidArchModule if none was set. For modules that
// called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
// the actual multilib in extraMultilib.
-func decodeMultilib(base *ModuleBase, os OsType) (multilib, extraMultilib string) {
+func decodeMultilib(base *ModuleBase, os OsType, ignorePrefer32OnDevice bool) (multilib, extraMultilib string) {
// First check the "android.compile_multilib" or "host.compile_multilib" properties.
switch os.Class {
case Device:
@@ -749,6 +702,13 @@
multilib = base.commonProperties.Default_multilib
}
+ // If a device is configured with multiple targets, this option
+ // force all device targets that prefer32 to be compiled only as
+ // the first target.
+ if ignorePrefer32OnDevice && os.Class == Device && (multilib == "prefer32" || multilib == "first_prefer32") {
+ multilib = "first"
+ }
+
if base.commonProperties.UseTargetVariants {
// Darwin has the concept of "universal binaries" which is implemented in Soong by
// building both x86_64 and arm64 variants, and having select module types know how to
@@ -990,19 +950,13 @@
if string(field.Tag) != `android:"`+strings.Join(values, ",")+`"` {
panic(fmt.Errorf("unexpected tag format %q", field.Tag))
}
- // don't delete path tag as it is needed for bp2build
// these tags don't need to be present in the runtime generated struct type.
- values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend"})
- if len(values) > 0 && values[0] != "path" {
+ values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path"})
+ if len(values) > 0 {
panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
- } else if len(values) == 1 {
- // FIXME(b/200678898): This assumes that the only tag type when there's
- // `android:"arch_variant"` is `android` itself and thus clobbers others
- field.Tag = reflect.StructTag(`android:"` + strings.Join(values, ",") + `"`)
- } else {
- field.Tag = ``
}
+ field.Tag = ``
return true, field
}
return false, field
@@ -1825,17 +1779,19 @@
for _, t := range targets {
if _, found := set[t.Os.String()]; !found {
set[t.Os.String()] = true
- ret = append(ret, commonTargetMap[t.Os.String()])
+ common := commonTargetMap[t.Os.String()]
+ common.HostCross = t.HostCross
+ ret = append(ret, common)
}
}
return ret
}
-// firstTarget takes a list of Targets and a list of multilib values and returns a list of Targets
+// FirstTarget takes a list of Targets and a list of multilib values and returns a list of Targets
// that contains zero or one Target for each OsType, selecting the one that matches the earliest
// filter.
-func firstTarget(targets []Target, filters ...string) []Target {
+func FirstTarget(targets []Target, filters ...string) []Target {
// find the first target from each OS
var ret []Target
hasHost := false
@@ -1865,9 +1821,9 @@
case "common_first":
buildTargets = getCommonTargets(targets)
if prefer32 {
- buildTargets = append(buildTargets, firstTarget(targets, "lib32", "lib64")...)
+ buildTargets = append(buildTargets, FirstTarget(targets, "lib32", "lib64")...)
} else {
- buildTargets = append(buildTargets, firstTarget(targets, "lib64", "lib32")...)
+ buildTargets = append(buildTargets, FirstTarget(targets, "lib64", "lib32")...)
}
case "both":
if prefer32 {
@@ -1883,12 +1839,12 @@
buildTargets = filterMultilibTargets(targets, "lib64")
case "first":
if prefer32 {
- buildTargets = firstTarget(targets, "lib32", "lib64")
+ buildTargets = FirstTarget(targets, "lib32", "lib64")
} else {
- buildTargets = firstTarget(targets, "lib64", "lib32")
+ buildTargets = FirstTarget(targets, "lib64", "lib32")
}
case "first_prefer32":
- buildTargets = firstTarget(targets, "lib32", "lib64")
+ buildTargets = FirstTarget(targets, "lib32", "lib64")
case "prefer32":
buildTargets = filterMultilibTargets(targets, "lib32")
if len(buildTargets) == 0 {
diff --git a/android/arch_test.go b/android/arch_test.go
index dd0b115..ad2076d 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -66,9 +66,9 @@
}{},
out: &struct {
A *string
- B *string `android:"path"`
- C *string `android:"path"`
- D *string `android:"path"`
+ B *string
+ C *string
+ D *string
}{},
filtered: true,
},
diff --git a/android/bazel.go b/android/bazel.go
index 40f2917..183a2f3 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -35,6 +35,20 @@
Bp2BuildTopLevel = "."
)
+type BazelConversionStatus struct {
+ // Information about _all_ bp2build targets generated by this module. Multiple targets are
+ // supported as Soong handles some things within a single target that we may choose to split into
+ // multiple targets, e.g. renderscript, protos, yacc within a cc module.
+ Bp2buildInfo []bp2buildInfo `blueprint:"mutated"`
+
+ // UnconvertedBp2buildDep stores the module names of direct dependency that were not converted to
+ // Bazel
+ UnconvertedDeps []string `blueprint:"mutated"`
+
+ // MissingBp2buildDep stores the module names of direct dependency that were not found
+ MissingDeps []string `blueprint:"mutated"`
+}
+
type bazelModuleProperties struct {
// The label of the Bazel target replacing this Soong module. When run in conversion mode, this
// will import the handcrafted build target into the autogenerated file. Note: this may result in
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 4d9423a..a5fa043 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -21,6 +21,7 @@
"io/ioutil"
"os"
"os/exec"
+ "path"
"path/filepath"
"runtime"
"strings"
@@ -28,17 +29,33 @@
"android/soong/bazel/cquery"
"android/soong/shared"
+
"github.com/google/blueprint"
"android/soong/bazel"
)
+var (
+ writeBazelFile = pctx.AndroidStaticRule("bazelWriteFileRule", blueprint.RuleParams{
+ Command: `sed "s/\\\\n/\n/g" ${out}.rsp >${out}`,
+ Rspfile: "${out}.rsp",
+ RspfileContent: "${content}",
+ }, "content")
+ _ = pctx.HostBinToolVariable("bazelBuildRunfilesTool", "build-runfiles")
+ buildRunfilesRule = pctx.AndroidStaticRule("bazelBuildRunfiles", blueprint.RuleParams{
+ Command: "${bazelBuildRunfilesTool} ${in} ${outDir}",
+ Depfile: "",
+ Description: "",
+ CommandDeps: []string{"${bazelBuildRunfilesTool}"},
+ }, "outDir")
+)
+
func init() {
RegisterMixedBuildsMutator(InitRegistrationContext)
}
func RegisterMixedBuildsMutator(ctx RegistrationContext) {
- ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
ctx.BottomUp("mixed_builds_prep", mixedBuildsPrepareMutator).Parallel()
})
}
@@ -75,6 +92,10 @@
osType OsType
}
+func (c configKey) String() string {
+ return fmt.Sprintf("%s::%s", c.arch, c.osType)
+}
+
// Map key to describe bazel cquery requests.
type cqueryKey struct {
label string
@@ -82,6 +103,11 @@
configKey configKey
}
+func (c cqueryKey) String() string {
+ return fmt.Sprintf("cquery(%s,%s,%s)", c.label, c.requestType.Name(), c.configKey)
+
+}
+
// BazelContext is a context object useful for interacting with Bazel during
// the course of a build. Use of Bazel to evaluate part of the build graph
// is referred to as a "mixed build". (Some modules are managed by Soong,
@@ -107,11 +133,14 @@
// TODO(b/232976601): Remove.
GetPythonBinary(label string, cfgKey configKey) (string, error)
+ // Returns the results of the GetApexInfo query (including output files)
+ GetApexInfo(label string, cfgkey configKey) (cquery.ApexCqueryInfo, error)
+
// ** end Cquery Results Retrieval Functions
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
- InvokeBazel() error
+ InvokeBazel(config Config) error
// Returns true if bazel is enabled for the given configuration.
BazelEnabled() bool
@@ -170,28 +199,33 @@
LabelToOutputFiles map[string][]string
LabelToCcInfo map[string]cquery.CcInfo
LabelToPythonBinary map[string]string
+ LabelToApexInfo map[string]cquery.ApexCqueryInfo
}
-func (m MockBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
+func (m MockBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
panic("unimplemented")
}
-func (m MockBazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, error) {
+func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, error) {
result, _ := m.LabelToOutputFiles[label]
return result, nil
}
-func (m MockBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
+func (m MockBazelContext) GetCcInfo(label string, _ configKey) (cquery.CcInfo, error) {
result, _ := m.LabelToCcInfo[label]
return result, nil
}
-func (m MockBazelContext) GetPythonBinary(label string, cfgKey configKey) (string, error) {
+func (m MockBazelContext) GetPythonBinary(label string, _ configKey) (string, error) {
result, _ := m.LabelToPythonBinary[label]
return result, nil
}
-func (m MockBazelContext) InvokeBazel() error {
+func (n MockBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) {
+ panic("unimplemented")
+}
+
+func (m MockBazelContext) InvokeBazel(_ Config) error {
panic("unimplemented")
}
@@ -245,23 +279,35 @@
return "", fmt.Errorf("no bazel response found for %v", key)
}
-func (n noopBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
+func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexCqueryInfo, error) {
+ key := cqueryKey{label, cquery.GetApexInfo, cfgKey}
+ if rawString, ok := bazelCtx.results[key]; ok {
+ return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString)), nil
+ }
+ return cquery.ApexCqueryInfo{}, fmt.Errorf("no bazel response found for %v", key)
+}
+
+func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
panic("unimplemented")
}
-func (n noopBazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, error) {
+func (n noopBazelContext) GetOutputFiles(_ string, _ configKey) ([]string, error) {
panic("unimplemented")
}
-func (n noopBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
+func (n noopBazelContext) GetCcInfo(_ string, _ configKey) (cquery.CcInfo, error) {
panic("unimplemented")
}
-func (n noopBazelContext) GetPythonBinary(label string, cfgKey configKey) (string, error) {
+func (n noopBazelContext) GetPythonBinary(_ string, _ configKey) (string, error) {
panic("unimplemented")
}
-func (n noopBazelContext) InvokeBazel() error {
+func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) {
+ panic("unimplemented")
+}
+
+func (n noopBazelContext) InvokeBazel(_ Config) error {
panic("unimplemented")
}
@@ -303,7 +349,7 @@
p := bazelPaths{
soongOutDir: c.soongOutDir,
}
- missingEnvVars := []string{}
+ var missingEnvVars []string
if len(c.Getenv("BAZEL_HOME")) > 1 {
p.homeDir = c.Getenv("BAZEL_HOME")
} else {
@@ -361,13 +407,13 @@
type mockBazelRunner struct {
bazelCommandResults map[bazelCommand]string
commands []bazelCommand
+ extraFlags []string
}
-func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
- runName bazel.RunName,
- command bazelCommand,
- extraFlags ...string) (string, string, error) {
+func (r *mockBazelRunner) issueBazelCommand(_ *bazelPaths, _ bazel.RunName,
+ command bazelCommand, extraFlags ...string) (string, string, error) {
r.commands = append(r.commands, command)
+ r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
if ret, ok := r.bazelCommandResults[command]; ok {
return ret, "", nil
}
@@ -383,50 +429,48 @@
func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand,
extraFlags ...string) (string, string, error) {
cmdFlags := []string{
- // --noautodetect_server_javabase has the practical consequence of preventing Bazel from
- // attempting to download rules_java, which is incompatible with
- // --experimental_repository_disable_download set further below.
- // rules_java is also not needed until mixed builds start building java targets.
- // TODO(b/197958133): Once rules_java is pulled into AOSP, remove this flag.
- "--noautodetect_server_javabase",
"--output_base=" + absolutePath(paths.outputBase),
command.command,
- }
- cmdFlags = append(cmdFlags, command.expression)
- cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(paths, runName))
+ command.expression,
+ // TODO(asmundak): is it needed in every build?
+ "--profile=" + shared.BazelMetricsFilename(paths, runName),
- // Set default platforms to canonicalized values for mixed builds requests.
- // If these are set in the bazelrc, they will have values that are
- // non-canonicalized to @sourceroot labels, and thus be invalid when
- // referenced from the buildroot.
- //
- // The actual platform values here may be overridden by configuration
- // transitions from the buildroot.
- cmdFlags = append(cmdFlags,
- fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_target"))
- cmdFlags = append(cmdFlags,
- fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"))
- // This should be parameterized on the host OS, but let's restrict to linux
- // to keep things simple for now.
- cmdFlags = append(cmdFlags,
- fmt.Sprintf("--host_platform=%s", "//build/bazel/platforms:linux_x86_64"))
+ // Set default platforms to canonicalized values for mixed builds requests.
+ // If these are set in the bazelrc, they will have values that are
+ // non-canonicalized to @sourceroot labels, and thus be invalid when
+ // referenced from the buildroot.
+ //
+ // The actual platform values here may be overridden by configuration
+ // transitions from the buildroot.
+ fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_target"),
+ fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"),
- // Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
- cmdFlags = append(cmdFlags, "--experimental_repository_disable_download")
+ // This should be parameterized on the host OS, but let's restrict to linux
+ // to keep things simple for now.
+ fmt.Sprintf("--host_platform=%s", "//build/bazel/platforms:linux_x86_64"),
+
+ // Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
+ "--experimental_repository_disable_download",
+
+ // Suppress noise
+ "--ui_event_filters=-INFO",
+ "--noshow_progress"}
cmdFlags = append(cmdFlags, extraFlags...)
bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
bazelCmd.Dir = absolutePath(paths.syntheticWorkspaceDir())
- bazelCmd.Env = append(os.Environ(),
- "HOME="+paths.homeDir,
+ extraEnv := []string{
+ "HOME=" + paths.homeDir,
pwdPrefix(),
- "BUILD_DIR="+absolutePath(paths.soongOutDir),
+ "BUILD_DIR=" + absolutePath(paths.soongOutDir),
// Make OUT_DIR absolute here so tools/bazel.sh uses the correct
// OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out.
- "OUT_DIR="+absolutePath(paths.outDir()),
+ "OUT_DIR=" + absolutePath(paths.outDir()),
// Disables local host detection of gcc; toolchain information is defined
// explicitly in BUILD files.
- "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1")
+ "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
+ }
+ bazelCmd.Env = append(os.Environ(), extraEnv...)
stderr := &bytes.Buffer{}
bazelCmd.Stderr = stderr
@@ -526,7 +570,7 @@
configNodesSection := ""
labelsByConfig := map[string][]string{}
- for val, _ := range context.requests {
+ for val := range context.requests {
labelString := fmt.Sprintf("\"@%s\"", val.label)
configString := getConfigString(val)
labelsByConfig[configString] = append(labelsByConfig[configString], labelString)
@@ -564,7 +608,7 @@
// request type.
func (context *bazelContext) cqueryStarlarkFileContents() []byte {
requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
- for val, _ := range context.requests {
+ for val := range context.requests {
cqueryId := getCqueryId(val)
mapEntryString := fmt.Sprintf("%q : True", cqueryId)
requestTypeToCqueryIdEntries[val.requestType] =
@@ -637,6 +681,15 @@
fail("expected platform name of the form 'android_<arch>' or 'linux_<arch>', but was " + str(platforms))
return "UNKNOWN"
+def json_for_file(key, file):
+ return '"' + key + '":"' + file.path + '"'
+
+def json_for_files(key, files):
+ return '"' + key + '":[' + ",".join(['"' + f.path + '"' for f in files]) + ']'
+
+def json_for_labels(key, ll):
+ return '"' + key + '":[' + ",".join(['"' + str(x) + '"' for x in ll]) + ']'
+
def format(target):
id_string = str(target.label) + "|" + get_arch(target)
@@ -676,11 +729,9 @@
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
-func (context *bazelContext) InvokeBazel() error {
+func (context *bazelContext) InvokeBazel(config Config) error {
context.results = make(map[cqueryKey]string)
- var cqueryOutput string
- var cqueryErr string
var err error
soongInjectionPath := absolutePath(context.paths.injectedFilesDir())
@@ -697,46 +748,28 @@
return err
}
}
- err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "WORKSPACE.bazel"), []byte{}, 0666)
- if err != nil {
+ if err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "WORKSPACE.bazel"), []byte{}, 0666); err != nil {
return err
}
-
- err = ioutil.WriteFile(
- filepath.Join(mixedBuildsPath, "main.bzl"),
- context.mainBzlFileContents(), 0666)
- if err != nil {
+ if err = ioutil.WriteFile(filepath.Join(mixedBuildsPath, "main.bzl"), context.mainBzlFileContents(), 0666); err != nil {
return err
}
-
- err = ioutil.WriteFile(
- filepath.Join(mixedBuildsPath, "BUILD.bazel"),
- context.mainBuildFileContents(), 0666)
- if err != nil {
+ if err = ioutil.WriteFile(filepath.Join(mixedBuildsPath, "BUILD.bazel"), context.mainBuildFileContents(), 0666); err != nil {
return err
}
cqueryFileRelpath := filepath.Join(context.paths.injectedFilesDir(), "buildroot.cquery")
- err = ioutil.WriteFile(
- absolutePath(cqueryFileRelpath),
- context.cqueryStarlarkFileContents(), 0666)
- if err != nil {
+ if err = ioutil.WriteFile(absolutePath(cqueryFileRelpath), context.cqueryStarlarkFileContents(), 0666); err != nil {
return err
}
- buildrootLabel := "@soong_injection//mixed_builds:buildroot"
- cqueryOutput, cqueryErr, err = context.issueBazelCommand(
- context.paths,
- bazel.CqueryBuildRootRunName,
- bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)},
- "--output=starlark",
- "--starlark:file="+absolutePath(cqueryFileRelpath))
- err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"),
- []byte(cqueryOutput), 0666)
+ const buildrootLabel = "@soong_injection//mixed_builds:buildroot"
+ cqueryCmd := bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)}
+ cqueryOutput, cqueryErr, err := context.issueBazelCommand(context.paths, bazel.CqueryBuildRootRunName, cqueryCmd,
+ "--output=starlark", "--starlark:file="+absolutePath(cqueryFileRelpath))
if err != nil {
return err
}
-
- if err != nil {
+ if err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryOutput), 0666); err != nil {
return err
}
@@ -747,7 +780,6 @@
cqueryResults[splitLine[0]] = splitLine[1]
}
}
-
for val := range context.requests {
if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok {
context.results[val] = cqueryResult
@@ -759,21 +791,27 @@
// Issue an aquery command to retrieve action information about the bazel build tree.
//
- // TODO(cparsons): Use --target_pattern_file to avoid command line limits.
- var aqueryOutput string
- aqueryOutput, _, err = context.issueBazelCommand(
- context.paths,
- bazel.AqueryBuildRootRunName,
- bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)},
- // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
- // proto sources, which would add a number of unnecessary dependencies.
- "--output=jsonproto")
-
- if err != nil {
- return err
+ // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
+ // proto sources, which would add a number of unnecessary dependencies.
+ extraFlags := []string{"--output=jsonproto", "--include_file_write_contents"}
+ if Bool(config.productVariables.ClangCoverage) {
+ extraFlags = append(extraFlags, "--collect_code_coverage")
+ paths := make([]string, 0, 2)
+ if p := config.productVariables.NativeCoveragePaths; len(p) > 0 {
+ paths = append(paths, JoinWithPrefixAndSeparator(p, "+", ","))
+ }
+ if p := config.productVariables.NativeCoverageExcludePaths; len(p) > 0 {
+ paths = append(paths, JoinWithPrefixAndSeparator(p, "-", ","))
+ }
+ if len(paths) > 0 {
+ extraFlags = append(extraFlags, "--instrumentation_filter="+strings.Join(paths, ","))
+ }
}
-
- context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
+ aqueryCmd := bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}
+ if aqueryOutput, _, err := context.issueBazelCommand(context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
+ extraFlags...); err == nil {
+ context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
+ }
if err != nil {
return err
}
@@ -781,12 +819,8 @@
// 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.paths,
- bazel.BazelBuildPhonyRootRunName,
- bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"})
-
- if err != nil {
+ buildCmd := bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"}
+ if _, _, err = context.issueBazelCommand(context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd); err != nil {
return err
}
@@ -852,61 +886,111 @@
})
}
- // Register bazel-owned build statements (obtained from the aquery invocation).
+ executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__")
+ bazelOutDir := path.Join(executionRoot, "bazel-out")
for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
- if len(buildStatement.Command) < 1 {
+ if len(buildStatement.Command) > 0 {
+ rule := NewRuleBuilder(pctx, ctx)
+ createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx)
+ desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths)
+ rule.Build(fmt.Sprintf("bazel %d", index), desc)
+ continue
+ }
+ // Certain actions returned by aquery (for instance FileWrite) do not contain a command
+ // and thus require special treatment. If BuildStatement were an interface implementing
+ // buildRule(ctx) function, the code here would just call it.
+ // Unfortunately, the BuildStatement is defined in
+ // the 'bazel' package, which cannot depend on 'android' package where ctx is defined,
+ // because this would cause circular dependency. So, until we move aquery processing
+ // to the 'android' package, we need to handle special cases here.
+ if buildStatement.Mnemonic == "FileWrite" || buildStatement.Mnemonic == "SourceSymlinkManifest" {
+ // Pass file contents as the value of the rule's "content" argument.
+ // Escape newlines and $ in the contents (the action "writeBazelFile" restores "\\n"
+ // back to the newline, and Ninja reads $$ as $.
+ escaped := strings.ReplaceAll(strings.ReplaceAll(buildStatement.FileContents, "\n", "\\n"),
+ "$", "$$")
+ ctx.Build(pctx, BuildParams{
+ Rule: writeBazelFile,
+ Output: PathForBazelOut(ctx, buildStatement.OutputPaths[0]),
+ Description: fmt.Sprintf("%s %s", buildStatement.Mnemonic, buildStatement.OutputPaths[0]),
+ Args: map[string]string{
+ "content": escaped,
+ },
+ })
+ } else if buildStatement.Mnemonic == "SymlinkTree" {
+ // build-runfiles arguments are the manifest file and the target directory
+ // where it creates the symlink tree according to this manifest (and then
+ // writes the MANIFEST file to it).
+ outManifest := PathForBazelOut(ctx, buildStatement.OutputPaths[0])
+ outManifestPath := outManifest.String()
+ if !strings.HasSuffix(outManifestPath, "MANIFEST") {
+ panic("the base name of the symlink tree action should be MANIFEST, got " + outManifestPath)
+ }
+ outDir := filepath.Dir(outManifestPath)
+ ctx.Build(pctx, BuildParams{
+ Rule: buildRunfilesRule,
+ Output: outManifest,
+ Inputs: []Path{PathForBazelOut(ctx, buildStatement.InputPaths[0])},
+ Description: "symlink tree for " + outDir,
+ Args: map[string]string{
+ "outDir": outDir,
+ },
+ })
+ } else {
panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
}
- rule := NewRuleBuilder(pctx, ctx)
- cmd := rule.Command()
+ }
+}
- // cd into Bazel's execution root, which is the action cwd.
- cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ &&", ctx.Config().BazelContext.OutputBase()))
+// Register bazel-owned build statements (obtained from the aquery invocation).
+func createCommand(cmd *RuleBuilderCommand, buildStatement bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx PathContext) {
+ // executionRoot is the action cwd.
+ cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot))
- // Remove old outputs, as some actions might not rerun if the outputs are detected.
- if len(buildStatement.OutputPaths) > 0 {
- cmd.Text("rm -f")
- for _, outputPath := range buildStatement.OutputPaths {
- cmd.Text(outputPath)
- }
- cmd.Text("&&")
- }
-
- for _, pair := range buildStatement.Env {
- // Set per-action env variables, if any.
- cmd.Flag(pair.Key + "=" + pair.Value)
- }
-
- // The actual Bazel action.
- cmd.Text(" " + buildStatement.Command)
-
+ // Remove old outputs, as some actions might not rerun if the outputs are detected.
+ if len(buildStatement.OutputPaths) > 0 {
+ cmd.Text("rm -f")
for _, outputPath := range buildStatement.OutputPaths {
- cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
+ cmd.Text(fmt.Sprintf("'%s'", outputPath))
}
- for _, inputPath := range buildStatement.InputPaths {
- cmd.Implicit(PathForBazelOut(ctx, inputPath))
- }
- for _, inputDepsetHash := range buildStatement.InputDepsetHashes {
- otherDepsetName := bazelDepsetName(inputDepsetHash)
- cmd.Implicit(PathForPhony(ctx, otherDepsetName))
- }
+ cmd.Text("&&")
+ }
- if depfile := buildStatement.Depfile; depfile != nil {
- cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile))
- }
+ for _, pair := range buildStatement.Env {
+ // Set per-action env variables, if any.
+ cmd.Flag(pair.Key + "=" + pair.Value)
+ }
- for _, symlinkPath := range buildStatement.SymlinkPaths {
- cmd.ImplicitSymlinkOutput(PathForBazelOut(ctx, symlinkPath))
- }
+ // The actual Bazel action.
+ cmd.Text(buildStatement.Command)
- // This is required to silence warnings pertaining to unexpected timestamps. Particularly,
- // some Bazel builtins (such as files in the bazel_tools directory) have far-future
- // timestamps. Without restat, Ninja would emit warnings that the input files of a
- // build statement have later timestamps than the outputs.
- rule.Restat()
+ for _, outputPath := range buildStatement.OutputPaths {
+ cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
+ }
+ for _, inputPath := range buildStatement.InputPaths {
+ cmd.Implicit(PathForBazelOut(ctx, inputPath))
+ }
+ for _, inputDepsetHash := range buildStatement.InputDepsetHashes {
+ otherDepsetName := bazelDepsetName(inputDepsetHash)
+ cmd.Implicit(PathForPhony(ctx, otherDepsetName))
+ }
- desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths)
- rule.Build(fmt.Sprintf("bazel %d", index), desc)
+ if depfile := buildStatement.Depfile; depfile != nil {
+ // The paths in depfile are relative to `executionRoot`.
+ // Hence, they need to be corrected by replacing "bazel-out"
+ // with the full `bazelOutDir`.
+ // Otherwise, implicit outputs and implicit inputs under "bazel-out/"
+ // would be deemed missing.
+ // (Note: The regexp uses a capture group because the version of sed
+ // does not support a look-behind pattern.)
+ replacement := fmt.Sprintf(`&& sed -i'' -E 's@(^|\s|")bazel-out/@\1%s/@g' '%s'`,
+ bazelOutDir, *depfile)
+ cmd.Text(replacement)
+ cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile))
+ }
+
+ for _, symlinkPath := range buildStatement.SymlinkPaths {
+ cmd.ImplicitSymlinkOutput(PathForBazelOut(ctx, symlinkPath))
}
}
@@ -917,15 +1001,22 @@
func getConfigString(key cqueryKey) string {
arch := key.configKey.arch
if len(arch) == 0 || arch == "common" {
- // Use host platform, which is currently hardcoded to be x86_64.
- arch = "x86_64"
+ if key.configKey.osType.Class == Device {
+ // For the generic Android, the expected result is "target|android", which
+ // corresponds to the product_variable_config named "android_target" in
+ // build/bazel/platforms/BUILD.bazel.
+ arch = "target"
+ } else {
+ // Use host platform, which is currently hardcoded to be x86_64.
+ arch = "x86_64"
+ }
}
- os := key.configKey.osType.Name
- if len(os) == 0 || os == "common_os" || os == "linux_glibc" {
+ osName := key.configKey.osType.Name
+ if len(osName) == 0 || osName == "common_os" || osName == "linux_glibc" {
// Use host OS, which is currently hardcoded to be linux.
- os = "linux"
+ osName = "linux"
}
- return arch + "|" + os
+ return arch + "|" + osName
}
func GetConfigKey(ctx BaseModuleContext) configKey {
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index cfdccd7..ec2541b 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -4,11 +4,14 @@
"os"
"path/filepath"
"reflect"
+ "strings"
"testing"
"android/soong/bazel/cquery"
)
+var testConfig = TestConfig("out", nil, "", nil)
+
func TestRequestResultsAfterInvokeBazel(t *testing.T) {
label := "//foo:bar"
cfg := configKey{"arm64_armv8-a", Android}
@@ -16,7 +19,7 @@
bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
})
bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg)
- err := bazelContext.InvokeBazel()
+ err := bazelContext.InvokeBazel(testConfig)
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
@@ -30,7 +33,7 @@
func TestInvokeBazelWritesBazelFiles(t *testing.T) {
bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
- err := bazelContext.InvokeBazel()
+ err := bazelContext.InvokeBazel(testConfig)
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
@@ -54,16 +57,17 @@
}
func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
- bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: `
+ type testCase struct {
+ input string
+ command string
+ }
+
+ var testCases = []testCase{
+ {`
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -73,28 +77,103 @@
"outputIds": [1],
"primaryOutputId": 1
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" }]
}`,
- })
- err := bazelContext.InvokeBazel()
+ "cd 'test/exec_root' && rm -f 'one' && touch foo",
+ }, {`
+{
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 10 },
+ { "id": 2, "pathFragmentId": 20 }],
+ "actions": [{
+ "targetId": 100,
+ "actionKey": "x",
+ "mnemonic": "x",
+ "arguments": ["bogus", "command"],
+ "outputIds": [1, 2],
+ "primaryOutputId": 1
+ }],
+ "pathFragments": [
+ { "id": 10, "label": "one", "parentId": 30 },
+ { "id": 20, "label": "one.d", "parentId": 30 },
+ { "id": 30, "label": "parent" }]
+}`,
+ `cd 'test/exec_root' && rm -f 'parent/one' && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1test/bazel_out/@g' 'parent/one.d'`,
+ },
+ }
+
+ for i, testCase := range testCases {
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
+ bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: testCase.input})
+
+ err := bazelContext.InvokeBazel(testConfig)
+ if err != nil {
+ t.Fatalf("testCase #%d: did not expect error invoking Bazel, but got %s", i+1, err)
+ }
+
+ got := bazelContext.BuildStatementsToRegister()
+ if want := 1; len(got) != want {
+ t.Fatalf("expected %d registered build statements, but got %#v", want, got)
+ }
+
+ cmd := RuleBuilderCommand{}
+ createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", PathContextForTesting(TestConfig("out", nil, "", nil)))
+ if actual, expected := cmd.buf.String(), testCase.command; expected != actual {
+ t.Errorf("expected: [%s], actual: [%s]", expected, actual)
+ }
+ }
+}
+
+func TestCoverageFlagsAfterInvokeBazel(t *testing.T) {
+ testConfig.productVariables.ClangCoverage = boolPtr(true)
+
+ testConfig.productVariables.NativeCoveragePaths = []string{"foo1", "foo2"}
+ testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1", "bar2"}
+ verifyExtraFlags(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`)
+
+ testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
+ testConfig.productVariables.NativeCoverageExcludePaths = nil
+ verifyExtraFlags(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`)
+
+ 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)
+ }
+}
+
+func verifyExtraFlags(t *testing.T, config Config, expected string) string {
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
+
+ err := bazelContext.InvokeBazel(config)
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
- got := bazelContext.BuildStatementsToRegister()
- if want := 1; len(got) != want {
- t.Errorf("Expected %d registered build statements, got %#v", want, got)
+ flags := bazelContext.bazelRunner.(*mockBazelRunner).extraFlags
+ if expected := 3; len(flags) != expected {
+ t.Errorf("Expected %d extra flags got %#v", expected, flags)
}
+
+ actual := flags[1]
+ if !strings.Contains(actual, expected) {
+ t.Errorf("Expected %#v got %#v", expected, actual)
+ }
+
+ return actual
}
func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index fa10f62..c030aa8 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -32,14 +32,14 @@
// There is often a similar method for Bazel as there is for Soong path handling and should be used
// in similar circumstances
//
-// Bazel Soong
-//
-// BazelLabelForModuleSrc PathForModuleSrc
-// BazelLabelForModuleSrcExcludes PathForModuleSrcExcludes
-// BazelLabelForModuleDeps n/a
-// tbd PathForSource
-// tbd ExistentPathsForSources
-// PathForBazelOut PathForModuleOut
+// Bazel Soong
+// ==============================================================
+// BazelLabelForModuleSrc PathForModuleSrc
+// BazelLabelForModuleSrcExcludes PathForModuleSrcExcludes
+// BazelLabelForModuleDeps n/a
+// tbd PathForSource
+// tbd ExistentPathsForSources
+// PathForBazelOut PathForModuleOut
//
// Use cases:
// * Module contains a property (often tagged `android:"path"`) that expects paths *relative to the
@@ -68,7 +68,7 @@
// cannot be resolved,the function will panic. This is often due to the dependency not being added
// via an AddDependency* method.
-// A minimal context interface to check if a module should be converted by bp2build,
+// BazelConversionContext is a minimal context interface to check if a module should be converted by bp2build,
// with functions containing information to match against allowlists and denylists.
// If a module is deemed to be convertible by bp2build, then it should rely on a
// BazelConversionPathContext for more functions for dep/path features.
@@ -449,25 +449,51 @@
return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
}
-// PathForBazelOut returns a Path representing the paths... under an output directory dedicated to
-// bazel-owned outputs.
-func PathForBazelOut(ctx PathContext, paths ...string) BazelOutPath {
- execRootPathComponents := append([]string{"execroot", "__main__"}, paths...)
- execRootPath := filepath.Join(execRootPathComponents...)
- validatedExecRootPath, err := validatePath(execRootPath)
+// PathForBazelOutRelative returns a BazelOutPath representing the path under an output directory dedicated to
+// bazel-owned outputs. Calling .Rel() on the result will give the input path as relative to the given
+// relativeRoot.
+func PathForBazelOutRelative(ctx PathContext, relativeRoot string, path string) BazelOutPath {
+ validatedPath, err := validatePath(filepath.Join("execroot", "__main__", path))
if err != nil {
reportPathError(ctx, err)
}
+ relativeRootPath := filepath.Join("execroot", "__main__", relativeRoot)
+ if pathComponents := strings.Split(path, "/"); len(pathComponents) >= 3 &&
+ pathComponents[0] == "bazel-out" && pathComponents[2] == "bin" {
+ // If the path starts with something like: bazel-out/linux_x86_64-fastbuild-ST-b4ef1c4402f9/bin/
+ // make it relative to that folder. bazel-out/volatile-status.txt is an example
+ // of something that starts with bazel-out but is not relative to the bin folder
+ relativeRootPath = filepath.Join("execroot", "__main__", pathComponents[0], pathComponents[1], pathComponents[2], relativeRoot)
+ }
- outputPath := OutputPath{basePath{"", ""},
+ var relPath string
+ if relPath, err = filepath.Rel(relativeRootPath, validatedPath); err != nil || strings.HasPrefix(relPath, "../") {
+ // We failed to make this path relative to execroot/__main__, fall back to a non-relative path
+ // One case where this happens is when path is ../bazel_tools/something
+ relativeRootPath = ""
+ relPath = validatedPath
+ }
+
+ outputPath := OutputPath{
+ basePath{"", ""},
ctx.Config().soongOutDir,
- ctx.Config().BazelContext.OutputBase()}
+ ctx.Config().BazelContext.OutputBase(),
+ }
return BazelOutPath{
- OutputPath: outputPath.withRel(validatedExecRootPath),
+ // .withRel() appends its argument onto the current path, and only the most
+ // recently appended part is returned by outputPath.rel().
+ // So outputPath.rel() will return relPath.
+ OutputPath: outputPath.withRel(relativeRootPath).withRel(relPath),
}
}
+// PathForBazelOut returns a BazelOutPath representing the path under an output directory dedicated to
+// bazel-owned outputs.
+func PathForBazelOut(ctx PathContext, path string) BazelOutPath {
+ return PathForBazelOutRelative(ctx, "", path)
+}
+
// PathsForBazelOut returns a list of paths representing the paths under an output directory
// dedicated to Bazel-owned outputs.
func PathsForBazelOut(ctx PathContext, paths []string) Paths {
diff --git a/android/bazel_paths_test.go b/android/bazel_paths_test.go
new file mode 100644
index 0000000..b047511
--- /dev/null
+++ b/android/bazel_paths_test.go
@@ -0,0 +1,108 @@
+// 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 android
+
+import (
+ "path/filepath"
+ "testing"
+)
+
+type TestBazelPathContext struct{}
+
+func (*TestBazelPathContext) Config() Config {
+ cfg := NullConfig("out", "out/soong")
+ cfg.BazelContext = MockBazelContext{
+ OutputBaseDir: "out/bazel",
+ }
+ return cfg
+}
+
+func (*TestBazelPathContext) AddNinjaFileDeps(deps ...string) {
+ panic("Unimplemented")
+}
+
+func TestPathForBazelOut(t *testing.T) {
+ ctx := &TestBazelPathContext{}
+ out := PathForBazelOut(ctx, "foo/bar/baz/boq.txt")
+ expectedPath := filepath.Join(ctx.Config().BazelContext.OutputBase(), "execroot/__main__/foo/bar/baz/boq.txt")
+ if out.String() != expectedPath {
+ t.Errorf("incorrect OutputPath: expected %q, got %q", expectedPath, out.String())
+ }
+
+ expectedRelPath := "foo/bar/baz/boq.txt"
+ if out.Rel() != expectedRelPath {
+ t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
+ }
+}
+
+func TestPathForBazelOutRelative(t *testing.T) {
+ ctx := &TestBazelPathContext{}
+ out := PathForBazelOutRelative(ctx, "foo/bar", "foo/bar/baz/boq.txt")
+
+ expectedPath := filepath.Join(ctx.Config().BazelContext.OutputBase(), "execroot/__main__/foo/bar/baz/boq.txt")
+ if out.String() != expectedPath {
+ t.Errorf("incorrect OutputPath: expected %q, got %q", expectedPath, out.String())
+ }
+
+ expectedRelPath := "baz/boq.txt"
+ if out.Rel() != expectedRelPath {
+ t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
+ }
+}
+
+func TestPathForBazelOutRelativeUnderBinFolder(t *testing.T) {
+ ctx := &TestBazelPathContext{}
+ out := PathForBazelOutRelative(ctx, "foo/bar", "bazel-out/linux_x86_64-fastbuild-ST-b4ef1c4402f9/bin/foo/bar/baz/boq.txt")
+
+ expectedPath := filepath.Join(ctx.Config().BazelContext.OutputBase(), "execroot/__main__/bazel-out/linux_x86_64-fastbuild-ST-b4ef1c4402f9/bin/foo/bar/baz/boq.txt")
+ if out.String() != expectedPath {
+ t.Errorf("incorrect OutputPath: expected %q, got %q", expectedPath, out.String())
+ }
+
+ expectedRelPath := "baz/boq.txt"
+ if out.Rel() != expectedRelPath {
+ t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
+ }
+}
+
+func TestPathForBazelOutOutsideOfExecroot(t *testing.T) {
+ ctx := &TestBazelPathContext{}
+ out := PathForBazelOut(ctx, "../bazel_tools/linux_x86_64-fastbuild/bin/tools/android/java_base_extras.jar")
+
+ expectedPath := filepath.Join(ctx.Config().BazelContext.OutputBase(), "execroot/bazel_tools/linux_x86_64-fastbuild/bin/tools/android/java_base_extras.jar")
+ if out.String() != expectedPath {
+ t.Errorf("incorrect OutputPath: expected %q, got %q", expectedPath, out.String())
+ }
+
+ expectedRelPath := "execroot/bazel_tools/linux_x86_64-fastbuild/bin/tools/android/java_base_extras.jar"
+ if out.Rel() != expectedRelPath {
+ t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
+ }
+}
+
+func TestPathForBazelOutRelativeWithParentDirectoryRoot(t *testing.T) {
+ ctx := &TestBazelPathContext{}
+ out := PathForBazelOutRelative(ctx, "../bazel_tools", "../bazel_tools/foo/bar/baz.sh")
+
+ expectedPath := filepath.Join(ctx.Config().BazelContext.OutputBase(), "execroot/bazel_tools/foo/bar/baz.sh")
+ if out.String() != expectedPath {
+ t.Errorf("incorrect OutputPath: expected %q, got %q", expectedPath, out.String())
+ }
+
+ expectedRelPath := "foo/bar/baz.sh"
+ if out.Rel() != expectedRelPath {
+ t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
+ }
+}
diff --git a/android/buildinfo_prop.go b/android/buildinfo_prop.go
index 6339a71..acebdbb 100644
--- a/android/buildinfo_prop.go
+++ b/android/buildinfo_prop.go
@@ -89,6 +89,7 @@
writeProp("ro.build.version.security_patch", config.PlatformSecurityPatch())
writeProp("ro.build.version.base_os", config.PlatformBaseOS())
writeProp("ro.build.version.min_supported_target_sdk", config.PlatformMinSupportedTargetSdkVersion())
+ writeProp("ro.build.version.known_codenames", config.PlatformVersionKnownCodenames())
if config.Eng() {
writeProp("ro.build.type", "eng")
@@ -109,7 +110,6 @@
writeProp("ro.build.display.id", $BUILD_DISPLAY_ID)
writeProp("ro.build.version.incremental", $BUILD_NUMBER)
writeProp("ro.build.version.preview_sdk_fingerprint", $PLATFORM_PREVIEW_SDK_FINGERPRINT)
- writeProp("ro.build.version.known_codenames", $PLATFORM_VERSION_KNOWN_CODENAMES)
writeProp("ro.build.version.release_or_preview_display", $PLATFORM_DISPLAY_VERSION)
writeProp("ro.build.date", `$DATE`)
writeProp("ro.build.date.utc", `$DATE +%s`)
diff --git a/android/config.go b/android/config.go
index eb01baa..d3f8ab4 100644
--- a/android/config.go
+++ b/android/config.go
@@ -18,8 +18,8 @@
// product variables necessary for soong_build's operation.
import (
+ "bytes"
"encoding/json"
- "errors"
"fmt"
"io/ioutil"
"os"
@@ -305,6 +305,9 @@
if err != nil {
return fmt.Errorf("cannot marshal config data: %s", err.Error())
}
+ // The backslashes need to be escaped because this text is going to be put
+ // inside a Starlark string literal.
+ configJson = bytes.ReplaceAll(configJson, []byte("\\"), []byte("\\\\"))
bzl := []string{
bazel.GeneratedBazelFileWarning,
@@ -317,11 +320,11 @@
arch_variant_product_var_constraints = _arch_variant_product_var_constraints
`,
}
- err = ioutil.WriteFile(filepath.Join(dir, "product_variables.bzl"), []byte(strings.Join(bzl, "\n")), 0644)
+ err = os.WriteFile(filepath.Join(dir, "product_variables.bzl"), []byte(strings.Join(bzl, "\n")), 0644)
if err != nil {
return fmt.Errorf("Could not write .bzl config file %s", err)
}
- err = ioutil.WriteFile(filepath.Join(dir, "BUILD"), []byte(bazel.GeneratedBazelFileWarning), 0644)
+ err = os.WriteFile(filepath.Join(dir, "BUILD"), []byte(bazel.GeneratedBazelFileWarning), 0644)
if err != nil {
return fmt.Errorf("Could not write BUILD config file %s", err)
}
@@ -341,123 +344,6 @@
}
}
-// TestConfig returns a Config object for testing.
-func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
- envCopy := make(map[string]string)
- for k, v := range env {
- envCopy[k] = v
- }
-
- // Copy the real PATH value to the test environment, it's needed by
- // NonHermeticHostSystemTool() used in x86_darwin_host.go
- envCopy["PATH"] = os.Getenv("PATH")
-
- config := &config{
- productVariables: productVariables{
- DeviceName: stringPtr("test_device"),
- DeviceProduct: stringPtr("test_product"),
- Platform_sdk_version: intPtr(30),
- Platform_sdk_codename: stringPtr("S"),
- Platform_base_sdk_extension_version: intPtr(1),
- Platform_version_active_codenames: []string{"S", "Tiramisu"},
- DeviceSystemSdkVersions: []string{"14", "15"},
- Platform_systemsdk_versions: []string{"29", "30"},
- AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
- AAPTPreferredConfig: stringPtr("xhdpi"),
- AAPTCharacteristics: stringPtr("nosdcard"),
- AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"},
- UncompressPrivAppDex: boolPtr(true),
- ShippingApiLevel: stringPtr("30"),
- },
-
- outDir: buildDir,
- soongOutDir: filepath.Join(buildDir, "soong"),
- captureBuild: true,
- env: envCopy,
-
- // Set testAllowNonExistentPaths so that test contexts don't need to specify every path
- // passed to PathForSource or PathForModuleSrc.
- TestAllowNonExistentPaths: true,
-
- BazelContext: noopBazelContext{},
- mixedBuildDisabledModules: make(map[string]struct{}),
- mixedBuildEnabledModules: make(map[string]struct{}),
- }
- config.deviceConfig = &deviceConfig{
- config: config,
- }
- config.TestProductVariables = &config.productVariables
-
- config.mockFileSystem(bp, fs)
-
- determineBuildOS(config)
-
- return Config{config}
-}
-
-func modifyTestConfigToSupportArchMutator(testConfig Config) {
- config := testConfig.config
-
- config.Targets = map[OsType][]Target{
- Android: []Target{
- {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false},
- {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false},
- },
- config.BuildOS: []Target{
- {config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
- {config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
- },
- }
-
- if runtime.GOOS == "darwin" {
- config.Targets[config.BuildOS] = config.Targets[config.BuildOS][:1]
- }
-
- config.BuildOSTarget = config.Targets[config.BuildOS][0]
- config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
- config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
- config.AndroidFirstDeviceTarget = firstTarget(config.Targets[Android], "lib64", "lib32")[0]
- config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
- config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
- config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
- config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon")
-}
-
-func modifyTestConfigForMusl(config Config) {
- delete(config.Targets, config.BuildOS)
- config.productVariables.HostMusl = boolPtr(true)
- determineBuildOS(config.config)
- config.Targets[config.BuildOS] = []Target{
- {config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
- {config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
- }
-
- config.BuildOSTarget = config.Targets[config.BuildOS][0]
- config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
-}
-
-// TestArchConfig returns a Config object suitable for using for tests that
-// need to run the arch mutator.
-func TestArchConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
- testConfig := TestConfig(buildDir, env, bp, fs)
- modifyTestConfigToSupportArchMutator(testConfig)
- return testConfig
-}
-
-// ConfigForAdditionalRun is a config object which is "reset" for another
-// bootstrap run. Only per-run data is reset. Data which needs to persist across
-// multiple runs in the same program execution is carried over (such as Bazel
-// context or environment deps).
-func ConfigForAdditionalRun(c Config) (Config, error) {
- newConfig, err := NewConfig(c.moduleListFile, c.runGoTests, c.outDir, c.soongOutDir, c.env)
- if err != nil {
- return Config{}, err
- }
- newConfig.BazelContext = c.BazelContext
- newConfig.envDeps = c.envDeps
- return newConfig, nil
-}
-
// NewConfig creates a new Config object. The srcDir argument specifies the path
// to the root source directory. It also loads the config file, if found.
func NewConfig(moduleListFile string, runGoTests bool, outDir, soongOutDir string, availableEnv map[string]string) (Config, error) {
@@ -554,7 +440,7 @@
// Compilation targets for Android.
if len(config.Targets[Android]) > 0 {
config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
- config.AndroidFirstDeviceTarget = firstTarget(config.Targets[Android], "lib64", "lib32")[0]
+ config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
}
config.BazelContext, err = NewBazelContext(config)
@@ -740,7 +626,8 @@
// these per device type.
//
// NOTE: Do not base conditional logic on this value. It may break product
-// inheritance.
+//
+// inheritance.
func (c *config) DeviceProduct() string {
return *c.productVariables.DeviceProduct
}
@@ -761,6 +648,10 @@
return uncheckedFinalApiLevel(*c.productVariables.Platform_sdk_version)
}
+func (c *config) PlatformSdkFinal() bool {
+ return Bool(c.productVariables.Platform_sdk_final)
+}
+
func (c *config) PlatformSdkCodename() string {
return String(c.productVariables.Platform_sdk_codename)
}
@@ -793,6 +684,10 @@
return String(c.productVariables.Platform_version_last_stable)
}
+func (c *config) PlatformVersionKnownCodenames() string {
+ return String(c.productVariables.Platform_version_known_codenames)
+}
+
func (c *config) MinSupportedSdkVersion() ApiLevel {
return uncheckedFinalApiLevel(19)
}
@@ -903,6 +798,15 @@
return PathForSource(ctx, filepath.Dir(defaultCert))
}
+// Certificate for the NetworkStack sepolicy context
+func (c *config) MainlineSepolicyDevCertificatesDir(ctx ModuleContext) SourcePath {
+ cert := String(c.productVariables.MainlineSepolicyDevCertificates)
+ if cert != "" {
+ return PathForSource(ctx, cert)
+ }
+ return c.DefaultAppCertificateDir(ctx)
+}
+
// AllowMissingDependencies configures Blueprint/Soong to not fail when modules
// are configured to depend on non-existent modules. Note that this does not
// affect missing input dependencies at the Ninja level.
@@ -1442,8 +1346,8 @@
return Bool(c.productVariables.ForceApexSymlinkOptimization)
}
-func (c *config) CompressedApex() bool {
- return Bool(c.productVariables.CompressedApex)
+func (c *config) ApexCompressionEnabled() bool {
+ return Bool(c.productVariables.CompressedApex) && !c.UnbundledBuildApps()
}
func (c *config) EnforceSystemCertificate() bool {
@@ -1693,6 +1597,10 @@
return InList(name, c.config.productVariables.BuildBrokenInputDirModules)
}
+func (c *deviceConfig) BuildBrokenDepfile() bool {
+ return Bool(c.config.productVariables.BuildBrokenDepfile)
+}
+
func (c *deviceConfig) RequiresInsecureExecmemForSwiftshader() bool {
return c.config.productVariables.RequiresInsecureExecmemForSwiftshader
}
@@ -1717,316 +1625,10 @@
return c.config.productVariables.GenerateAidlNdkPlatformBackend
}
-// The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
-// Such lists are used in the build system for things like bootclasspath jars or system server jars.
-// The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
-// module name. The pairs come from Make product variables as a list of colon-separated strings.
-//
-// Examples:
-// - "com.android.art:core-oj"
-// - "platform:framework"
-// - "system_ext:foo"
-//
-type ConfiguredJarList struct {
- // A list of apex components, which can be an apex name,
- // or special names like "platform" or "system_ext".
- apexes []string
-
- // A list of jar module name components.
- jars []string
+func (c *config) IgnorePrefer32OnDevice() bool {
+ return c.productVariables.IgnorePrefer32OnDevice
}
-// Len returns the length of the list of jars.
-func (l *ConfiguredJarList) Len() int {
- return len(l.jars)
-}
-
-// Jar returns the idx-th jar component of (apex, jar) pairs.
-func (l *ConfiguredJarList) Jar(idx int) string {
- return l.jars[idx]
-}
-
-// Apex returns the idx-th apex component of (apex, jar) pairs.
-func (l *ConfiguredJarList) Apex(idx int) string {
- return l.apexes[idx]
-}
-
-// ContainsJar returns true if the (apex, jar) pairs contains a pair with the
-// given jar module name.
-func (l *ConfiguredJarList) ContainsJar(jar string) bool {
- return InList(jar, l.jars)
-}
-
-// If the list contains the given (apex, jar) pair.
-func (l *ConfiguredJarList) containsApexJarPair(apex, jar string) bool {
- for i := 0; i < l.Len(); i++ {
- if apex == l.apexes[i] && jar == l.jars[i] {
- return true
- }
- }
- return false
-}
-
-// ApexOfJar returns the apex component of the first pair with the given jar name on the list, or
-// an empty string if not found.
-func (l *ConfiguredJarList) ApexOfJar(jar string) string {
- if idx := IndexList(jar, l.jars); idx != -1 {
- return l.Apex(IndexList(jar, l.jars))
- }
- return ""
-}
-
-// IndexOfJar returns the first pair with the given jar name on the list, or -1
-// if not found.
-func (l *ConfiguredJarList) IndexOfJar(jar string) int {
- return IndexList(jar, l.jars)
-}
-
-func copyAndAppend(list []string, item string) []string {
- // Create the result list to be 1 longer than the input.
- result := make([]string, len(list)+1)
-
- // Copy the whole input list into the result.
- count := copy(result, list)
-
- // Insert the extra item at the end.
- result[count] = item
-
- return result
-}
-
-// Append an (apex, jar) pair to the list.
-func (l *ConfiguredJarList) Append(apex string, jar string) ConfiguredJarList {
- // Create a copy of the backing arrays before appending to avoid sharing backing
- // arrays that are mutated across instances.
- apexes := copyAndAppend(l.apexes, apex)
- jars := copyAndAppend(l.jars, jar)
-
- return ConfiguredJarList{apexes, jars}
-}
-
-// Append a list of (apex, jar) pairs to the list.
-func (l *ConfiguredJarList) AppendList(other *ConfiguredJarList) ConfiguredJarList {
- apexes := make([]string, 0, l.Len()+other.Len())
- jars := make([]string, 0, l.Len()+other.Len())
-
- apexes = append(apexes, l.apexes...)
- jars = append(jars, l.jars...)
-
- apexes = append(apexes, other.apexes...)
- jars = append(jars, other.jars...)
-
- return ConfiguredJarList{apexes, jars}
-}
-
-// RemoveList filters out a list of (apex, jar) pairs from the receiving list of pairs.
-func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) ConfiguredJarList {
- apexes := make([]string, 0, l.Len())
- jars := make([]string, 0, l.Len())
-
- for i, jar := range l.jars {
- apex := l.apexes[i]
- if !list.containsApexJarPair(apex, jar) {
- apexes = append(apexes, apex)
- jars = append(jars, jar)
- }
- }
-
- return ConfiguredJarList{apexes, jars}
-}
-
-// Filter keeps the entries if a jar appears in the given list of jars to keep. Returns a new list
-// and any remaining jars that are not on this list.
-func (l *ConfiguredJarList) Filter(jarsToKeep []string) (ConfiguredJarList, []string) {
- var apexes []string
- var jars []string
-
- for i, jar := range l.jars {
- if InList(jar, jarsToKeep) {
- apexes = append(apexes, l.apexes[i])
- jars = append(jars, jar)
- }
- }
-
- return ConfiguredJarList{apexes, jars}, RemoveListFromList(jarsToKeep, jars)
-}
-
-// CopyOfJars returns a copy of the list of strings containing jar module name
-// components.
-func (l *ConfiguredJarList) CopyOfJars() []string {
- return CopyOf(l.jars)
-}
-
-// CopyOfApexJarPairs returns a copy of the list of strings with colon-separated
-// (apex, jar) pairs.
-func (l *ConfiguredJarList) CopyOfApexJarPairs() []string {
- pairs := make([]string, 0, l.Len())
-
- for i, jar := range l.jars {
- apex := l.apexes[i]
- pairs = append(pairs, apex+":"+jar)
- }
-
- return pairs
-}
-
-// BuildPaths returns a list of build paths based on the given directory prefix.
-func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths {
- paths := make(WritablePaths, l.Len())
- for i, jar := range l.jars {
- paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar")
- }
- return paths
-}
-
-// BuildPathsByModule returns a map from module name to build paths based on the given directory
-// prefix.
-func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath {
- paths := map[string]WritablePath{}
- for _, jar := range l.jars {
- paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar")
- }
- return paths
-}
-
-// UnmarshalJSON converts JSON configuration from raw bytes into a
-// ConfiguredJarList structure.
-func (l *ConfiguredJarList) UnmarshalJSON(b []byte) error {
- // Try and unmarshal into a []string each item of which contains a pair
- // <apex>:<jar>.
- var list []string
- err := json.Unmarshal(b, &list)
- if err != nil {
- // Did not work so return
- return err
- }
-
- apexes, jars, err := splitListOfPairsIntoPairOfLists(list)
- if err != nil {
- return err
- }
- l.apexes = apexes
- l.jars = jars
- return nil
-}
-
-func (l *ConfiguredJarList) MarshalJSON() ([]byte, error) {
- if len(l.apexes) != len(l.jars) {
- return nil, errors.New(fmt.Sprintf("Inconsistent ConfiguredJarList: apexes: %q, jars: %q", l.apexes, l.jars))
- }
-
- list := make([]string, 0, len(l.apexes))
-
- for i := 0; i < len(l.apexes); i++ {
- list = append(list, l.apexes[i]+":"+l.jars[i])
- }
-
- return json.Marshal(list)
-}
-
-// ModuleStem hardcodes the stem of framework-minus-apex to return "framework".
-//
-// TODO(b/139391334): hard coded until we find a good way to query the stem of a
-// module before any other mutators are run.
-func ModuleStem(module string) string {
- if module == "framework-minus-apex" {
- return "framework"
- }
- return module
-}
-
-// DevicePaths computes the on-device paths for the list of (apex, jar) pairs,
-// based on the operating system.
-func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string {
- paths := make([]string, l.Len())
- for i, jar := range l.jars {
- apex := l.apexes[i]
- name := ModuleStem(jar) + ".jar"
-
- var subdir string
- if apex == "platform" {
- subdir = "system/framework"
- } else if apex == "system_ext" {
- subdir = "system_ext/framework"
- } else {
- subdir = filepath.Join("apex", apex, "javalib")
- }
-
- if ostype.Class == Host {
- paths[i] = filepath.Join(cfg.Getenv("OUT_DIR"), "host", cfg.PrebuiltOS(), subdir, name)
- } else {
- paths[i] = filepath.Join("/", subdir, name)
- }
- }
- return paths
-}
-
-func (l *ConfiguredJarList) String() string {
- var pairs []string
- for i := 0; i < l.Len(); i++ {
- pairs = append(pairs, l.apexes[i]+":"+l.jars[i])
- }
- return strings.Join(pairs, ",")
-}
-
-func splitListOfPairsIntoPairOfLists(list []string) ([]string, []string, error) {
- // Now we need to populate this list by splitting each item in the slice of
- // pairs and appending them to the appropriate list of apexes or jars.
- apexes := make([]string, len(list))
- jars := make([]string, len(list))
-
- for i, apexjar := range list {
- apex, jar, err := splitConfiguredJarPair(apexjar)
- if err != nil {
- return nil, nil, err
- }
- apexes[i] = apex
- jars[i] = jar
- }
-
- return apexes, jars, nil
-}
-
-// Expected format for apexJarValue = <apex name>:<jar name>
-func splitConfiguredJarPair(str string) (string, string, error) {
- pair := strings.SplitN(str, ":", 2)
- if len(pair) == 2 {
- apex := pair[0]
- jar := pair[1]
- if apex == "" {
- return apex, jar, fmt.Errorf("invalid apex '%s' in <apex>:<jar> pair '%s', expected format: <apex>:<jar>", apex, str)
- }
- return apex, jar, nil
- } else {
- return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
- }
-}
-
-// CreateTestConfiguredJarList is a function to create ConfiguredJarList for tests.
-func CreateTestConfiguredJarList(list []string) ConfiguredJarList {
- // Create the ConfiguredJarList in as similar way as it is created at runtime by marshalling to
- // a json list of strings and then unmarshalling into a ConfiguredJarList instance.
- b, err := json.Marshal(list)
- if err != nil {
- panic(err)
- }
-
- var jarList ConfiguredJarList
- err = json.Unmarshal(b, &jarList)
- if err != nil {
- panic(err)
- }
-
- return jarList
-}
-
-// EmptyConfiguredJarList returns an empty jar list.
-func EmptyConfiguredJarList() ConfiguredJarList {
- return ConfiguredJarList{}
-}
-
-var earlyBootJarsKey = NewOnceKey("earlyBootJars")
-
func (c *config) BootJars() []string {
return c.Once(earlyBootJarsKey, func() interface{} {
list := c.productVariables.BootJars.CopyOfJars()
diff --git a/android/configured_jars.go b/android/configured_jars.go
new file mode 100644
index 0000000..53fef05
--- /dev/null
+++ b/android/configured_jars.go
@@ -0,0 +1,314 @@
+// 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 android
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "path/filepath"
+ "strings"
+)
+
+// The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
+// Such lists are used in the build system for things like bootclasspath jars or system server jars.
+// The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
+// module name. The pairs come from Make product variables as a list of colon-separated strings.
+//
+// Examples:
+// - "com.android.art:core-oj"
+// - "platform:framework"
+// - "system_ext:foo"
+type ConfiguredJarList struct {
+ // A list of apex components, which can be an apex name,
+ // or special names like "platform" or "system_ext".
+ apexes []string
+
+ // A list of jar module name components.
+ jars []string
+}
+
+// Len returns the length of the list of jars.
+func (l *ConfiguredJarList) Len() int {
+ return len(l.jars)
+}
+
+// Jar returns the idx-th jar component of (apex, jar) pairs.
+func (l *ConfiguredJarList) Jar(idx int) string {
+ return l.jars[idx]
+}
+
+// Apex returns the idx-th apex component of (apex, jar) pairs.
+func (l *ConfiguredJarList) Apex(idx int) string {
+ return l.apexes[idx]
+}
+
+// ContainsJar returns true if the (apex, jar) pairs contains a pair with the
+// given jar module name.
+func (l *ConfiguredJarList) ContainsJar(jar string) bool {
+ return InList(jar, l.jars)
+}
+
+// If the list contains the given (apex, jar) pair.
+func (l *ConfiguredJarList) containsApexJarPair(apex, jar string) bool {
+ for i := 0; i < l.Len(); i++ {
+ if apex == l.apexes[i] && jar == l.jars[i] {
+ return true
+ }
+ }
+ return false
+}
+
+// ApexOfJar returns the apex component of the first pair with the given jar name on the list, or
+// an empty string if not found.
+func (l *ConfiguredJarList) ApexOfJar(jar string) string {
+ if idx := IndexList(jar, l.jars); idx != -1 {
+ return l.Apex(IndexList(jar, l.jars))
+ }
+ return ""
+}
+
+// IndexOfJar returns the first pair with the given jar name on the list, or -1
+// if not found.
+func (l *ConfiguredJarList) IndexOfJar(jar string) int {
+ return IndexList(jar, l.jars)
+}
+
+func copyAndAppend(list []string, item string) []string {
+ // Create the result list to be 1 longer than the input.
+ result := make([]string, len(list)+1)
+
+ // Copy the whole input list into the result.
+ count := copy(result, list)
+
+ // Insert the extra item at the end.
+ result[count] = item
+
+ return result
+}
+
+// Append an (apex, jar) pair to the list.
+func (l *ConfiguredJarList) Append(apex string, jar string) ConfiguredJarList {
+ // Create a copy of the backing arrays before appending to avoid sharing backing
+ // arrays that are mutated across instances.
+ apexes := copyAndAppend(l.apexes, apex)
+ jars := copyAndAppend(l.jars, jar)
+
+ return ConfiguredJarList{apexes, jars}
+}
+
+// Append a list of (apex, jar) pairs to the list.
+func (l *ConfiguredJarList) AppendList(other *ConfiguredJarList) ConfiguredJarList {
+ apexes := make([]string, 0, l.Len()+other.Len())
+ jars := make([]string, 0, l.Len()+other.Len())
+
+ apexes = append(apexes, l.apexes...)
+ jars = append(jars, l.jars...)
+
+ apexes = append(apexes, other.apexes...)
+ jars = append(jars, other.jars...)
+
+ return ConfiguredJarList{apexes, jars}
+}
+
+// RemoveList filters out a list of (apex, jar) pairs from the receiving list of pairs.
+func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) ConfiguredJarList {
+ apexes := make([]string, 0, l.Len())
+ jars := make([]string, 0, l.Len())
+
+ for i, jar := range l.jars {
+ apex := l.apexes[i]
+ if !list.containsApexJarPair(apex, jar) {
+ apexes = append(apexes, apex)
+ jars = append(jars, jar)
+ }
+ }
+
+ return ConfiguredJarList{apexes, jars}
+}
+
+// Filter keeps the entries if a jar appears in the given list of jars to keep. Returns a new list
+// and any remaining jars that are not on this list.
+func (l *ConfiguredJarList) Filter(jarsToKeep []string) (ConfiguredJarList, []string) {
+ var apexes []string
+ var jars []string
+
+ for i, jar := range l.jars {
+ if InList(jar, jarsToKeep) {
+ apexes = append(apexes, l.apexes[i])
+ jars = append(jars, jar)
+ }
+ }
+
+ return ConfiguredJarList{apexes, jars}, RemoveListFromList(jarsToKeep, jars)
+}
+
+// CopyOfJars returns a copy of the list of strings containing jar module name
+// components.
+func (l *ConfiguredJarList) CopyOfJars() []string {
+ return CopyOf(l.jars)
+}
+
+// CopyOfApexJarPairs returns a copy of the list of strings with colon-separated
+// (apex, jar) pairs.
+func (l *ConfiguredJarList) CopyOfApexJarPairs() []string {
+ pairs := make([]string, 0, l.Len())
+
+ for i, jar := range l.jars {
+ apex := l.apexes[i]
+ pairs = append(pairs, apex+":"+jar)
+ }
+
+ return pairs
+}
+
+// BuildPaths returns a list of build paths based on the given directory prefix.
+func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths {
+ paths := make(WritablePaths, l.Len())
+ for i, jar := range l.jars {
+ paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar")
+ }
+ return paths
+}
+
+// BuildPathsByModule returns a map from module name to build paths based on the given directory
+// prefix.
+func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath {
+ paths := map[string]WritablePath{}
+ for _, jar := range l.jars {
+ paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar")
+ }
+ return paths
+}
+
+// UnmarshalJSON converts JSON configuration from raw bytes into a
+// ConfiguredJarList structure.
+func (l *ConfiguredJarList) UnmarshalJSON(b []byte) error {
+ // Try and unmarshal into a []string each item of which contains a pair
+ // <apex>:<jar>.
+ var list []string
+ err := json.Unmarshal(b, &list)
+ if err != nil {
+ // Did not work so return
+ return err
+ }
+
+ apexes, jars, err := splitListOfPairsIntoPairOfLists(list)
+ if err != nil {
+ return err
+ }
+ l.apexes = apexes
+ l.jars = jars
+ return nil
+}
+
+func (l *ConfiguredJarList) MarshalJSON() ([]byte, error) {
+ if len(l.apexes) != len(l.jars) {
+ return nil, errors.New(fmt.Sprintf("Inconsistent ConfiguredJarList: apexes: %q, jars: %q", l.apexes, l.jars))
+ }
+
+ list := make([]string, 0, len(l.apexes))
+
+ for i := 0; i < len(l.apexes); i++ {
+ list = append(list, l.apexes[i]+":"+l.jars[i])
+ }
+
+ return json.Marshal(list)
+}
+
+// ModuleStem hardcodes the stem of framework-minus-apex to return "framework".
+//
+// TODO(b/139391334): hard coded until we find a good way to query the stem of a
+// module before any other mutators are run.
+func ModuleStem(module string) string {
+ if module == "framework-minus-apex" {
+ return "framework"
+ }
+ return module
+}
+
+// DevicePaths computes the on-device paths for the list of (apex, jar) pairs,
+// based on the operating system.
+func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string {
+ paths := make([]string, l.Len())
+ for i, jar := range l.jars {
+ apex := l.apexes[i]
+ name := ModuleStem(jar) + ".jar"
+
+ var subdir string
+ if apex == "platform" {
+ subdir = "system/framework"
+ } else if apex == "system_ext" {
+ subdir = "system_ext/framework"
+ } else {
+ subdir = filepath.Join("apex", apex, "javalib")
+ }
+
+ if ostype.Class == Host {
+ paths[i] = filepath.Join(cfg.Getenv("OUT_DIR"), "host", cfg.PrebuiltOS(), subdir, name)
+ } else {
+ paths[i] = filepath.Join("/", subdir, name)
+ }
+ }
+ return paths
+}
+
+func (l *ConfiguredJarList) String() string {
+ var pairs []string
+ for i := 0; i < l.Len(); i++ {
+ pairs = append(pairs, l.apexes[i]+":"+l.jars[i])
+ }
+ return strings.Join(pairs, ",")
+}
+
+func splitListOfPairsIntoPairOfLists(list []string) ([]string, []string, error) {
+ // Now we need to populate this list by splitting each item in the slice of
+ // pairs and appending them to the appropriate list of apexes or jars.
+ apexes := make([]string, len(list))
+ jars := make([]string, len(list))
+
+ for i, apexjar := range list {
+ apex, jar, err := splitConfiguredJarPair(apexjar)
+ if err != nil {
+ return nil, nil, err
+ }
+ apexes[i] = apex
+ jars[i] = jar
+ }
+
+ return apexes, jars, nil
+}
+
+// Expected format for apexJarValue = <apex name>:<jar name>
+func splitConfiguredJarPair(str string) (string, string, error) {
+ pair := strings.SplitN(str, ":", 2)
+ if len(pair) == 2 {
+ apex := pair[0]
+ jar := pair[1]
+ if apex == "" {
+ return apex, jar, fmt.Errorf("invalid apex '%s' in <apex>:<jar> pair '%s', expected format: <apex>:<jar>", apex, str)
+ }
+ return apex, jar, nil
+ } else {
+ return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
+ }
+}
+
+// EmptyConfiguredJarList returns an empty jar list.
+func EmptyConfiguredJarList() ConfiguredJarList {
+ return ConfiguredJarList{}
+}
+
+var earlyBootJarsKey = NewOnceKey("earlyBootJars")
diff --git a/android/deapexer.go b/android/deapexer.go
index 265f531..6a93f60 100644
--- a/android/deapexer.go
+++ b/android/deapexer.go
@@ -15,6 +15,8 @@
package android
import (
+ "strings"
+
"github.com/google/blueprint"
)
@@ -148,12 +150,19 @@
func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo {
var di *DeapexerInfo
ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) {
- p := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo)
+ c := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo)
+ p := &c
if di != nil {
+ // If two DeapexerInfo providers have been found then check if they are
+ // equivalent. If they are then use the selected one, otherwise fail.
+ if selected := equivalentDeapexerInfoProviders(di, p); selected != nil {
+ di = selected
+ return
+ }
ctx.ModuleErrorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s",
di.ApexModuleName(), p.ApexModuleName())
}
- di = &p
+ di = p
})
if di != nil {
return di
@@ -162,3 +171,33 @@
ctx.ModuleErrorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName)
return nil
}
+
+// removeCompressedApexSuffix removes the _compressed suffix from the name if present.
+func removeCompressedApexSuffix(name string) string {
+ return strings.TrimSuffix(name, "_compressed")
+}
+
+// equivalentDeapexerInfoProviders checks to make sure that the two DeapexerInfo structures are
+// equivalent.
+//
+// At the moment <x> and <x>_compressed APEXes are treated as being equivalent.
+//
+// If they are not equivalent then this returns nil, otherwise, this returns the DeapexerInfo that
+// should be used by the build, which is always the uncompressed one. That ensures that the behavior
+// of the build is not dependent on which prebuilt APEX is visited first.
+func equivalentDeapexerInfoProviders(p1 *DeapexerInfo, p2 *DeapexerInfo) *DeapexerInfo {
+ n1 := removeCompressedApexSuffix(p1.ApexModuleName())
+ n2 := removeCompressedApexSuffix(p2.ApexModuleName())
+
+ // If the names don't match then they are not equivalent.
+ if n1 != n2 {
+ return nil
+ }
+
+ // Select the uncompressed APEX.
+ if n1 == removeCompressedApexSuffix(n1) {
+ return p1
+ } else {
+ return p2
+ }
+}
diff --git a/android/defaults.go b/android/defaults.go
index 8b121f6..54f44bc 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -15,6 +15,8 @@
package android
import (
+ "bytes"
+ "fmt"
"reflect"
"github.com/google/blueprint"
@@ -67,9 +69,11 @@
// Set the property structures into which defaults will be added.
setProperties(props []interface{}, variableProperties interface{})
- // Apply defaults from the supplied Defaults to the property structures supplied to
+ // Apply defaults from the supplied DefaultsModule to the property structures supplied to
// setProperties(...).
- applyDefaults(TopDownMutatorContext, []Defaults)
+ applyDefaults(TopDownMutatorContext, []DefaultsModule)
+
+ applySingleDefaultsWithTracker(EarlyModuleContext, DefaultsModule, defaultsTrackerFunc)
// Set the hook to be called after any defaults have been applied.
//
@@ -115,9 +119,23 @@
Defaults_visibility []string
}
+// AdditionalDefaultsProperties contains properties of defaults modules which
+// can have other defaults applied.
+type AdditionalDefaultsProperties struct {
+
+ // The list of properties set by the default whose values must not be changed by any module that
+ // applies these defaults. It is an error if a property is not supported by the defaults module or
+ // has not been set to a non-zero value. If this contains "*" then that must be the only entry in
+ // which case all properties that are set on this defaults will be protected (except the
+ // protected_properties and visibility.
+ Protected_properties []string
+}
+
type DefaultsModuleBase struct {
DefaultableModuleBase
+ defaultsProperties AdditionalDefaultsProperties
+
// Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
// target. This is primarily useful for modules that were architecture specific and instead are
// handled in Bazel as a select().
@@ -151,6 +169,18 @@
// DefaultsModuleBase will type-assert to the Defaults interface.
isDefaults() bool
+ // additionalDefaultableProperties returns additional properties provided by the defaults which
+ // can themselves have defaults applied.
+ additionalDefaultableProperties() []interface{}
+
+ // protectedProperties returns the names of the properties whose values cannot be changed by a
+ // module that applies these defaults.
+ protectedProperties() []string
+
+ // setProtectedProperties sets the names of the properties whose values cannot be changed by a
+ // module that applies these defaults.
+ setProtectedProperties(protectedProperties []string)
+
// Get the structures containing the properties for which defaults can be provided.
properties() []interface{}
@@ -167,6 +197,18 @@
Bazelable
}
+func (d *DefaultsModuleBase) additionalDefaultableProperties() []interface{} {
+ return []interface{}{&d.defaultsProperties}
+}
+
+func (d *DefaultsModuleBase) protectedProperties() []string {
+ return d.defaultsProperties.Protected_properties
+}
+
+func (d *DefaultsModuleBase) setProtectedProperties(protectedProperties []string) {
+ d.defaultsProperties.Protected_properties = protectedProperties
+}
+
func (d *DefaultsModuleBase) properties() []interface{} {
return d.defaultableProperties
}
@@ -190,6 +232,10 @@
&ApexProperties{},
&distProperties{})
+ // Additional properties of defaults modules that can themselves have
+ // defaults applied.
+ module.AddProperties(module.additionalDefaultableProperties()...)
+
// Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
InitBazelModule(module)
initAndroidModuleBase(module)
@@ -218,6 +264,57 @@
// The applicable licenses property for defaults is 'licenses'.
setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses)
+ AddLoadHook(module, func(ctx LoadHookContext) {
+
+ protectedProperties := module.protectedProperties()
+ if len(protectedProperties) == 0 {
+ return
+ }
+
+ propertiesAvailable := map[string]struct{}{}
+ propertiesSet := map[string]struct{}{}
+
+ // A defaults tracker which will keep track of which properties have been set on this module.
+ collector := func(defaults DefaultsModule, property string, dstValue interface{}, srcValue interface{}) bool {
+ value := reflect.ValueOf(dstValue)
+ propertiesAvailable[property] = struct{}{}
+ if !value.IsZero() {
+ propertiesSet[property] = struct{}{}
+ }
+ // Skip all the properties so that there are no changes to the defaults.
+ return false
+ }
+
+ // Try and apply this module's defaults to itself, so that the properties can be collected but
+ // skip all the properties so it doesn't actually do anything.
+ module.applySingleDefaultsWithTracker(ctx, module, collector)
+
+ if InList("*", protectedProperties) {
+ if len(protectedProperties) != 1 {
+ ctx.PropertyErrorf("protected_properties", `if specified then "*" must be the only property listed`)
+ return
+ }
+
+ // Do not automatically protect the protected_properties property.
+ delete(propertiesSet, "protected_properties")
+
+ // Or the visibility property.
+ delete(propertiesSet, "visibility")
+
+ // Replace the "*" with the names of all the properties that have been set.
+ protectedProperties = SortedStringKeys(propertiesSet)
+ module.setProtectedProperties(protectedProperties)
+ } else {
+ for _, property := range protectedProperties {
+ if _, ok := propertiesAvailable[property]; !ok {
+ ctx.PropertyErrorf(property, "property is not supported by this module type %q",
+ ctx.ModuleType())
+ } else if _, ok := propertiesSet[property]; !ok {
+ ctx.PropertyErrorf(property, "is not set; protected properties must be explicitly set")
+ }
+ }
+ }
+ })
}
var _ Defaults = (*DefaultsModuleBase)(nil)
@@ -269,35 +366,204 @@
b.setNamespacedVariableProps(dst)
}
+// defaultValueInfo contains information about each default value that applies to a protected
+// property.
+type defaultValueInfo struct {
+ // The DefaultsModule providing the value, which may be defined on that module or applied as a
+ // default from other modules.
+ module Module
+
+ // The default value, as returned by getComparableValue
+ defaultValue reflect.Value
+}
+
+// protectedPropertyInfo contains information about each property that has to be protected when
+// applying defaults.
+type protectedPropertyInfo struct {
+ // True if the property was set on the module to which defaults are applied, this is an error.
+ propertySet bool
+
+ // The original value of the property on the module, as returned by getComparableValue.
+ originalValue reflect.Value
+
+ // A list of defaults for the property that are being applied.
+ defaultValues []defaultValueInfo
+}
+
+// getComparableValue takes a reflect.Value that may be a pointer to another value and returns a
+// reflect.Value to the underlying data or the original if was not a pointer or was nil. The
+// returned values can then be compared for equality.
+func getComparableValue(value reflect.Value) reflect.Value {
+ if value.IsZero() {
+ return value
+ }
+ for value.Kind() == reflect.Ptr {
+ value = value.Elem()
+ }
+ return value
+}
+
func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
- defaultsList []Defaults) {
+ defaultsList []DefaultsModule) {
+
+ // Collate information on all the properties protected by each of the default modules applied
+ // to this module.
+ allProtectedProperties := map[string]*protectedPropertyInfo{}
+ for _, defaults := range defaultsList {
+ for _, property := range defaults.protectedProperties() {
+ info := allProtectedProperties[property]
+ if info == nil {
+ info = &protectedPropertyInfo{}
+ allProtectedProperties[property] = info
+ }
+ }
+ }
+
+ // If there are any protected properties then collate information about attempts to change them.
+ var protectedPropertyInfoCollector defaultsTrackerFunc
+ if len(allProtectedProperties) > 0 {
+ protectedPropertyInfoCollector = func(defaults DefaultsModule, property string,
+ dstValue interface{}, srcValue interface{}) bool {
+
+ // If the property is not protected then return immediately.
+ info := allProtectedProperties[property]
+ if info == nil {
+ return true
+ }
+
+ currentValue := reflect.ValueOf(dstValue)
+ if info.defaultValues == nil {
+ info.propertySet = !currentValue.IsZero()
+ info.originalValue = getComparableValue(currentValue)
+ }
+
+ defaultValue := reflect.ValueOf(srcValue)
+ if !defaultValue.IsZero() {
+ info.defaultValues = append(info.defaultValues,
+ defaultValueInfo{defaults, getComparableValue(defaultValue)})
+ }
+
+ return true
+ }
+ }
for _, defaults := range defaultsList {
if ctx.Config().runningAsBp2Build {
applyNamespacedVariableDefaults(defaults, ctx)
}
- for _, prop := range defaultable.defaultableProperties {
- if prop == defaultable.defaultableVariableProperties {
- defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
- } else {
- defaultable.applyDefaultProperties(ctx, defaults, prop)
+
+ defaultable.applySingleDefaultsWithTracker(ctx, defaults, protectedPropertyInfoCollector)
+ }
+
+ // Check the status of any protected properties.
+ for property, info := range allProtectedProperties {
+ if len(info.defaultValues) == 0 {
+ // No defaults were applied to the protected properties. Possibly because this module type
+ // does not support any of them.
+ continue
+ }
+
+ // Check to make sure that there are no conflicts between the defaults.
+ conflictingDefaults := false
+ previousDefaultValue := reflect.ValueOf(false)
+ for _, defaultInfo := range info.defaultValues {
+ defaultValue := defaultInfo.defaultValue
+ if previousDefaultValue.IsZero() {
+ previousDefaultValue = defaultValue
+ } else if !reflect.DeepEqual(previousDefaultValue.Interface(), defaultValue.Interface()) {
+ conflictingDefaults = true
+ break
}
}
+
+ if conflictingDefaults {
+ var buf bytes.Buffer
+ for _, defaultInfo := range info.defaultValues {
+ buf.WriteString(fmt.Sprintf("\n defaults module %q provides value %#v",
+ ctx.OtherModuleName(defaultInfo.module), defaultInfo.defaultValue))
+ }
+ result := buf.String()
+ ctx.ModuleErrorf("has conflicting default values for protected property %q:%s", property, result)
+ continue
+ }
+
+ // Now check to see whether there the current module tried to override/append to the defaults.
+ if info.propertySet {
+ originalValue := info.originalValue
+ // Just compare against the first defaults.
+ defaultValue := info.defaultValues[0].defaultValue
+ defaults := info.defaultValues[0].module
+
+ if originalValue.Kind() == reflect.Slice {
+ ctx.ModuleErrorf("attempts to append %q to protected property %q's value of %q defined in module %q",
+ originalValue,
+ property,
+ defaultValue,
+ ctx.OtherModuleName(defaults))
+ } else {
+ same := reflect.DeepEqual(originalValue.Interface(), defaultValue.Interface())
+ message := ""
+ if same {
+ message = fmt.Sprintf(" with a matching value (%#v) so this property can simply be removed.", originalValue)
+ } else {
+ message = fmt.Sprintf(" with a different value (override %#v with %#v) so removing the property may necessitate other changes.", defaultValue, originalValue)
+ }
+ ctx.ModuleErrorf("attempts to override protected property %q defined in module %q%s",
+ property,
+ ctx.OtherModuleName(defaults), message)
+ }
+ }
+ }
+}
+
+func (defaultable *DefaultableModuleBase) applySingleDefaultsWithTracker(ctx EarlyModuleContext, defaults DefaultsModule, tracker defaultsTrackerFunc) {
+ for _, prop := range defaultable.defaultableProperties {
+ var err error
+ if prop == defaultable.defaultableVariableProperties {
+ err = defaultable.applyDefaultVariableProperties(defaults, prop, tracker)
+ } else {
+ err = defaultable.applyDefaultProperties(defaults, prop, tracker)
+ }
+ if err != nil {
+ if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+ ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+ } else {
+ panic(err)
+ }
+ }
+ }
+}
+
+// defaultsTrackerFunc is the type of a function that can be used to track how defaults are applied.
+type defaultsTrackerFunc func(defaults DefaultsModule, property string,
+ dstValue interface{}, srcValue interface{}) bool
+
+// filterForTracker wraps a defaultsTrackerFunc in a proptools.ExtendPropertyFilterFunc
+func filterForTracker(defaults DefaultsModule, tracker defaultsTrackerFunc) proptools.ExtendPropertyFilterFunc {
+ if tracker == nil {
+ return nil
+ }
+ return func(property string,
+ dstField, srcField reflect.StructField,
+ dstValue, srcValue interface{}) (bool, error) {
+
+ apply := tracker(defaults, property, dstValue, srcValue)
+ return apply, nil
}
}
// Product variable properties need special handling, the type of the filtered product variable
// property struct may not be identical between the defaults module and the defaultable module.
// Use PrependMatchingProperties to apply whichever properties match.
-func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
- defaults Defaults, defaultableProp interface{}) {
+func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(defaults DefaultsModule,
+ defaultableProp interface{}, tracker defaultsTrackerFunc) error {
if defaultableProp == nil {
- return
+ return nil
}
defaultsProp := defaults.productVariableProperties()
if defaultsProp == nil {
- return
+ return nil
}
dst := []interface{}{
@@ -307,31 +573,26 @@
proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
}
- err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
- if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
- }
+ filter := filterForTracker(defaults, tracker)
+
+ return proptools.PrependMatchingProperties(dst, defaultsProp, filter)
}
-func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
- defaults Defaults, defaultableProp interface{}) {
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(defaults DefaultsModule,
+ defaultableProp interface{}, checker defaultsTrackerFunc) error {
+
+ filter := filterForTracker(defaults, checker)
for _, def := range defaults.properties() {
if proptools.TypeEqual(defaultableProp, def) {
- err := proptools.PrependProperties(defaultableProp, def, nil)
+ err := proptools.PrependProperties(defaultableProp, def, filter)
if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
+ return err
}
}
}
+
+ return nil
}
func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
@@ -348,12 +609,12 @@
func defaultsMutator(ctx TopDownMutatorContext) {
if defaultable, ok := ctx.Module().(Defaultable); ok {
if len(defaultable.defaults().Defaults) > 0 {
- var defaultsList []Defaults
+ var defaultsList []DefaultsModule
seen := make(map[Defaults]bool)
ctx.WalkDeps(func(module, parent Module) bool {
if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
- if defaults, ok := module.(Defaults); ok {
+ if defaults, ok := module.(DefaultsModule); ok {
if !seen[defaults] {
seen[defaults] = true
defaultsList = append(defaultsList, defaults)
diff --git a/android/defaults_test.go b/android/defaults_test.go
index a7542ab..d80f40c 100644
--- a/android/defaults_test.go
+++ b/android/defaults_test.go
@@ -19,7 +19,14 @@
)
type defaultsTestProperties struct {
- Foo []string
+ Foo []string
+ Bar []string
+ Nested struct {
+ Fizz *bool
+ }
+ Other struct {
+ Buzz *string
+ }
}
type defaultsTestModule struct {
@@ -130,3 +137,167 @@
// TODO: missing transitive defaults is currently not handled
_ = missingTransitiveDefaults
}
+
+func TestProtectedProperties_ProtectedPropertyNotSet(t *testing.T) {
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["foo"],
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
+ "module \"transitive\": foo: is not set; protected properties must be explicitly set")).
+ RunTest(t)
+}
+
+func TestProtectedProperties_ProtectedPropertyNotLeaf(t *testing.T) {
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["nested"],
+ nested: {
+ fizz: true,
+ },
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\Qmodule "transitive": nested: property is not supported by this module type "defaults"\E`)).
+ RunTest(t)
+}
+
+// TestProtectedProperties_ApplyDefaults makes sure that the protected_properties property has
+// defaults applied.
+func TestProtectedProperties_HasDefaultsApplied(t *testing.T) {
+
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["foo"],
+ foo: ["transitive"],
+ }
+
+ defaults {
+ name: "defaults",
+ defaults: ["transitive"],
+ protected_properties: ["bar"],
+ bar: ["defaults"],
+ }
+ `
+
+ result := GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ defaults := result.Module("defaults", "").(DefaultsModule)
+ AssertDeepEquals(t, "defaults protected properties", []string{"foo", "bar"}, defaults.protectedProperties())
+}
+
+// TestProtectedProperties_ProtectAllProperties makes sure that protected_properties: ["*"] protects
+// all properties.
+func TestProtectedProperties_ProtectAllProperties(t *testing.T) {
+
+ bp := `
+ defaults {
+ name: "transitive",
+ protected_properties: ["other.buzz"],
+ other: {
+ buzz: "transitive",
+ },
+ }
+
+ defaults {
+ name: "defaults",
+ defaults: ["transitive"],
+ visibility: ["//visibility:private"],
+ protected_properties: ["*"],
+ foo: ["other"],
+ bar: ["defaults"],
+ nested: {
+ fizz: true,
+ }
+ }
+ `
+
+ result := GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ defaults := result.Module("defaults", "").(DefaultsModule)
+ AssertDeepEquals(t, "defaults protected properties", []string{"other.buzz", "bar", "foo", "nested.fizz"},
+ defaults.protectedProperties())
+}
+
+func TestProtectedProperties_DetectedOverride(t *testing.T) {
+ bp := `
+ defaults {
+ name: "defaults",
+ protected_properties: ["foo", "nested.fizz"],
+ foo: ["defaults"],
+ nested: {
+ fizz: true,
+ },
+ }
+
+ test {
+ name: "foo",
+ defaults: ["defaults"],
+ foo: ["module"],
+ nested: {
+ fizz: false,
+ },
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ `\Qmodule "foo": attempts to append ["module"] to protected property "foo"'s value of ["defaults"] defined in module "defaults"\E`,
+ `\Qmodule "foo": attempts to override protected property "nested.fizz" defined in module "defaults" with a different value (override true with false) so removing the property may necessitate other changes.\E`,
+ })).RunTest(t)
+}
+
+func TestProtectedProperties_DefaultsConflict(t *testing.T) {
+ bp := `
+ defaults {
+ name: "defaults1",
+ protected_properties: ["other.buzz"],
+ other: {
+ buzz: "value",
+ },
+ }
+
+ defaults {
+ name: "defaults2",
+ protected_properties: ["other.buzz"],
+ other: {
+ buzz: "another",
+ },
+ }
+
+ test {
+ name: "foo",
+ defaults: ["defaults1", "defaults2"],
+ }
+ `
+
+ GroupFixturePreparers(
+ prepareForDefaultsTest,
+ FixtureWithRootAndroidBp(bp),
+ ).ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\Qmodule "foo": has conflicting default values for protected property "other.buzz":
+ defaults module "defaults1" provides value "value"
+ defaults module "defaults2" provides value "another"\E`,
+ )).RunTest(t)
+}
diff --git a/android/defs.go b/android/defs.go
index 362b382..2a28e98 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -68,7 +68,7 @@
CpExecutable = pctx.AndroidStaticRule("CpExecutable",
blueprint.RuleParams{
- Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out && chmod +x $out$extraCmds",
+ Command: "rm -f $out && cp $cpFlags $in $out && chmod +x $out$extraCmds",
Description: "cp $out",
},
"cpFlags", "extraCmds")
diff --git a/android/filegroup.go b/android/filegroup.go
index 485e0b9..9e5769a 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -116,6 +116,23 @@
return module
}
+var _ blueprint.JSONActionSupplier = (*fileGroup)(nil)
+
+func (fg *fileGroup) JSONActions() []blueprint.JSONAction {
+ ins := make([]string, 0, len(fg.srcs))
+ outs := make([]string, 0, len(fg.srcs))
+ for _, p := range fg.srcs {
+ ins = append(ins, p.String())
+ outs = append(outs, p.Rel())
+ }
+ return []blueprint.JSONAction{
+ blueprint.JSONAction{
+ Inputs: ins,
+ Outputs: outs,
+ },
+ }
+}
+
func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
fg.srcs = PathsForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs)
if fg.properties.Path != nil {
@@ -161,8 +178,7 @@
bazelOuts := make(Paths, 0, len(filePaths))
for _, p := range filePaths {
- src := PathForBazelOut(ctx, p)
- bazelOuts = append(bazelOuts, src)
+ bazelOuts = append(bazelOuts, PathForBazelOutRelative(ctx, ctx.ModuleDir(), p))
}
fg.srcs = bazelOuts
diff --git a/android/gen_notice.go b/android/gen_notice.go
index fda91ac..e2b839f 100644
--- a/android/gen_notice.go
+++ b/android/gen_notice.go
@@ -67,7 +67,12 @@
if ctx.Failed() {
return
}
- out(ctx, gm.output, ctx.ModuleName(gm), proptools.StringDefault(gm.properties.ArtifactName, defaultName), "", modules...)
+ out(ctx, gm.output, ctx.ModuleName(gm),
+ proptools.StringDefault(gm.properties.ArtifactName, defaultName),
+ []string{
+ ctx.Config().OutDir() + "/",
+ ctx.Config().SoongOutDir() + "/",
+ }, modules...)
})
}
diff --git a/android/gen_notice_test.go b/android/gen_notice_test.go
new file mode 100644
index 0000000..4ad2ecf
--- /dev/null
+++ b/android/gen_notice_test.go
@@ -0,0 +1,164 @@
+package android
+
+import (
+ "testing"
+
+ "github.com/google/blueprint"
+)
+
+var genNoticeTests = []struct {
+ name string
+ fs MockFS
+ expectedErrors []string
+}{
+ {
+ name: "gen_notice must not accept licenses property",
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ gen_notice {
+ name: "top_license",
+ licenses: ["other_license"],
+ }`),
+ },
+ expectedErrors: []string{
+ `unrecognized property "licenses"`,
+ },
+ },
+ {
+ name: "bad gen_notice",
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ gen_notice {
+ name: "top_notice",
+ for: ["top_rule"],
+ }`),
+ "other/Android.bp": []byte(`
+ mock_genrule {
+ name: "other_rule",
+ dep: ["top_notice"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "top_notice": for: no "top_rule" module exists`,
+ },
+ },
+ {
+ name: "doubly bad gen_notice",
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ gen_notice {
+ name: "top_notice",
+ for: ["top_rule", "other_rule"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "top_notice": for: modules "top_rule", "other_rule" do not exist`,
+ },
+ },
+ {
+ name: "good gen_notice",
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ gen_notice {
+ name: "top_notice",
+ for: ["top_rule"],
+ }
+
+ mock_genrule {
+ name: "top_rule",
+ dep: ["top_notice"],
+ }`),
+ "other/Android.bp": []byte(`
+ mock_genrule {
+ name: "other_rule",
+ dep: ["top_notice"],
+ }`),
+ },
+ },
+ {
+ name: "multiple license kinds",
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ gen_notice {
+ name: "top_notice",
+ for: ["top_rule"],
+ }
+
+ gen_notice {
+ name: "top_html_notice",
+ html: true,
+ for: ["top_rule"],
+ }
+
+ gen_notice {
+ name: "top_xml_notice",
+ xml: true,
+ for: ["top_notice"],
+ }
+
+ mock_genrule {
+ name: "top_rule",
+ dep: [
+ "top_notice",
+ "top_html_notice",
+ "top_xml_notice",
+ ],
+ }`),
+ "other/Android.bp": []byte(`
+ mock_genrule {
+ name: "other_rule",
+ dep: ["top_xml_notice"],
+ }`),
+ },
+ },
+}
+
+func TestGenNotice(t *testing.T) {
+ for _, test := range genNoticeTests {
+ t.Run(test.name, func(t *testing.T) {
+ GroupFixturePreparers(
+ PrepareForTestWithGenNotice,
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.RegisterModuleType("mock_genrule", newMockGenruleModule)
+ }),
+ test.fs.AddToFixture(),
+ ).
+ ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
+ RunTest(t)
+ })
+ }
+}
+
+type mockGenruleProperties struct {
+ Dep []string
+}
+
+type mockGenruleModule struct {
+ ModuleBase
+ DefaultableModuleBase
+
+ properties mockGenruleProperties
+}
+
+func newMockGenruleModule() Module {
+ m := &mockGenruleModule{}
+ m.AddProperties(&m.properties)
+ InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+ InitDefaultableModule(m)
+ return m
+}
+
+type genruleDepTag struct {
+ blueprint.BaseDependencyTag
+}
+
+func (j *mockGenruleModule) DepsMutator(ctx BottomUpMutatorContext) {
+ m, ok := ctx.Module().(Module)
+ if !ok {
+ return
+ }
+ ctx.AddDependency(m, genruleDepTag{}, j.properties.Dep...)
+}
+
+func (p *mockGenruleModule) GenerateAndroidBuildActions(ModuleContext) {
+}
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 6a5b0da..4ee5bf7 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -15,7 +15,6 @@
package android
import (
- "fmt"
"sort"
"strings"
@@ -67,6 +66,11 @@
return
}
+ // Defaults add properties and dependencies that get processed on their own.
+ if ctx.OtherModuleDependencyTag(dep) == DefaultsDepTag {
+ return
+ }
+
if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) {
info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo)
allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
@@ -105,7 +109,7 @@
if p := base.commonProperties.Effective_package_name; p != nil {
args = append(args,
- "-p "+proptools.NinjaAndShellEscape(*p))
+ `-p `+proptools.NinjaAndShellEscapeIncludingSpaces(*p))
}
args = append(args,
@@ -139,8 +143,6 @@
if len(outputFiles) > 0 {
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(outputFiles.Strings()), "-t "))
- } else {
- args = append(args, fmt.Sprintf("-t //%s:%s", ctx.ModuleDir(), ctx.ModuleName()))
}
// Installed files
diff --git a/android/licenses.go b/android/licenses.go
index 81c557e..c47b3e6 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -331,6 +331,8 @@
func licensesMakeVarsProvider(ctx MakeVarsContext) {
ctx.Strict("BUILD_LICENSE_METADATA",
ctx.Config().HostToolPath(ctx, "build_license_metadata").String())
+ ctx.Strict("COPY_LICENSE_METADATA",
+ ctx.Config().HostToolPath(ctx, "copy_license_metadata").String())
ctx.Strict("HTMLNOTICE", ctx.Config().HostToolPath(ctx, "htmlnotice").String())
ctx.Strict("XMLNOTICE", ctx.Config().HostToolPath(ctx, "xmlnotice").String())
ctx.Strict("TEXTNOTICE", ctx.Config().HostToolPath(ctx, "textnotice").String())
diff --git a/android/makevars.go b/android/makevars.go
index ece7091..a74185a 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -472,7 +472,8 @@
fmt.Fprintf(buf, "\tchmod +x $@\n")
}
if extraFiles := install.extraFiles; extraFiles != nil {
- fmt.Fprintf(buf, "\tunzip -qDD -d '%s' '%s'\n", extraFiles.dir.String(), extraFiles.zip.String())
+ fmt.Fprintf(buf, "\t( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} ) || \\\n", extraFiles.dir.String(), extraFiles.zip.String())
+ fmt.Fprintf(buf, "\t ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )\n")
}
fmt.Fprintln(buf)
}
diff --git a/android/metrics.go b/android/metrics.go
index 1580f82..ecda026 100644
--- a/android/metrics.go
+++ b/android/metrics.go
@@ -32,8 +32,13 @@
Variants int
}
-func ReadSoongMetrics(config Config) SoongMetrics {
- return config.Get(soongMetricsOnceKey).(SoongMetrics)
+func readSoongMetrics(config Config) (SoongMetrics, bool) {
+ soongMetrics, ok := config.Peek(soongMetricsOnceKey)
+ if ok {
+ return soongMetrics.(SoongMetrics), true
+ } else {
+ return SoongMetrics{}, false
+ }
}
func init() {
@@ -60,9 +65,11 @@
func collectMetrics(config Config, eventHandler metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics {
metrics := &soong_metrics_proto.SoongBuildMetrics{}
- soongMetrics := ReadSoongMetrics(config)
- metrics.Modules = proto.Uint32(uint32(soongMetrics.Modules))
- metrics.Variants = proto.Uint32(uint32(soongMetrics.Variants))
+ soongMetrics, ok := readSoongMetrics(config)
+ if ok {
+ metrics.Modules = proto.Uint32(uint32(soongMetrics.Modules))
+ metrics.Variants = proto.Uint32(uint32(soongMetrics.Variants))
+ }
memStats := runtime.MemStats{}
runtime.ReadMemStats(&memStats)
diff --git a/android/module.go b/android/module.go
index 21d5a3d..450dba9 100644
--- a/android/module.go
+++ b/android/module.go
@@ -35,10 +35,6 @@
var (
DeviceSharedLibrary = "shared_library"
DeviceStaticLibrary = "static_library"
- DeviceExecutable = "executable"
- HostSharedLibrary = "host_shared_library"
- HostStaticLibrary = "host_static_library"
- HostExecutable = "host_executable"
)
type BuildParams struct {
@@ -515,7 +511,6 @@
ExportedToMake() bool
InitRc() Paths
VintfFragments() Paths
- NoticeFiles() Paths
EffectiveLicenseFiles() Paths
AddProperties(props ...interface{})
@@ -831,9 +826,6 @@
// names of other modules to install on target if this module is installed
Target_required []string `android:"arch_variant"`
- // relative path to a file to include in the list of notices for the device
- Notice *string `android:"path"`
-
// The OsType of artifacts that this module variant is responsible for creating.
//
// Set by osMutator
@@ -913,17 +905,8 @@
// constants in image.go, but can also be set to a custom value by individual module types.
ImageVariation string `blueprint:"mutated"`
- // Information about _all_ bp2build targets generated by this module. Multiple targets are
- // supported as Soong handles some things within a single target that we may choose to split into
- // multiple targets, e.g. renderscript, protos, yacc within a cc module.
- Bp2buildInfo []bp2buildInfo `blueprint:"mutated"`
-
- // UnconvertedBp2buildDep stores the module names of direct dependency that were not converted to
- // Bazel
- UnconvertedBp2buildDeps []string `blueprint:"mutated"`
-
- // MissingBp2buildDep stores the module names of direct dependency that were not found
- MissingBp2buildDeps []string `blueprint:"mutated"`
+ // Bazel conversion status
+ BazelConversionStatus BazelConversionStatus `blueprint:"mutated"`
}
// CommonAttributes represents the common Bazel attributes from which properties
@@ -993,8 +976,8 @@
}
func MakeDefaultDistFiles(paths ...Path) TaggedDistFiles {
- for _, path := range paths {
- if path == nil {
+ for _, p := range paths {
+ if p == nil {
panic("The path to a dist file cannot be nil.")
}
}
@@ -1018,7 +1001,6 @@
MultilibFirst Multilib = "first"
MultilibCommon Multilib = "common"
MultilibCommonFirst Multilib = "common_first"
- MultilibDefault Multilib = ""
)
type HostOrDeviceSupported int
@@ -1162,52 +1144,113 @@
func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext,
enabledPropertyOverrides bazel.BoolAttribute) constraintAttributes {
- // Assert passed-in attributes include Name
- name := attrs.Name
- if len(name) == 0 {
- ctx.ModuleErrorf("CommonAttributes in fillCommonBp2BuildModuleAttrs expects a `.Name`!")
- }
mod := ctx.Module().base()
- props := &mod.commonProperties
+ // Assert passed-in attributes include Name
+ if len(attrs.Name) == 0 {
+ ctx.ModuleErrorf("CommonAttributes in fillCommonBp2BuildModuleAttrs expects a `.Name`!")
+ }
depsToLabelList := func(deps []string) bazel.LabelListAttribute {
return bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, deps))
}
- data := &attrs.Data
-
- required := depsToLabelList(props.Required)
- archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
-
var enabledProperty bazel.BoolAttribute
- if props.Enabled != nil {
- enabledProperty.Value = props.Enabled
+
+ onlyAndroid := false
+ neitherHostNorDevice := false
+
+ osSupport := map[string]bool{}
+
+ // if the target is enabled and supports arch variance, determine the defaults based on the module
+ // type's host or device property and host_supported/device_supported properties
+ if mod.commonProperties.ArchSpecific {
+ moduleSupportsDevice := mod.DeviceSupported()
+ moduleSupportsHost := mod.HostSupported()
+ if moduleSupportsHost && !moduleSupportsDevice {
+ // for host only, we specify as unsupported on android rather than listing all host osSupport
+ // TODO(b/220874839): consider replacing this with a constraint that covers all host osSupport
+ // instead
+ enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, Android.Name, proptools.BoolPtr(false))
+ } else if moduleSupportsDevice && !moduleSupportsHost {
+ enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, Android.Name, proptools.BoolPtr(true))
+ // specify as a positive to ensure any target-specific enabled can be resolved
+ // also save that a target is only android, as if there is only the positive restriction on
+ // android, it'll be dropped, so we may need to add it back later
+ onlyAndroid = true
+ } else if !moduleSupportsHost && !moduleSupportsDevice {
+ neitherHostNorDevice = true
+ }
+
+ for _, osType := range OsTypeList() {
+ if osType.Class == Host {
+ osSupport[osType.Name] = moduleSupportsHost
+ } else if osType.Class == Device {
+ osSupport[osType.Name] = moduleSupportsDevice
+ }
+ }
}
- for axis, configToProps := range archVariantProps {
- for config, _props := range configToProps {
- if archProps, ok := _props.(*commonProperties); ok {
- required.SetSelectValue(axis, config, depsToLabelList(archProps.Required).Value)
- if archProps.Enabled != nil {
- enabledProperty.SetSelectValue(axis, config, archProps.Enabled)
+ if neitherHostNorDevice {
+ // we can't build this, disable
+ enabledProperty.Value = proptools.BoolPtr(false)
+ } else if mod.commonProperties.Enabled != nil {
+ enabledProperty.SetValue(mod.commonProperties.Enabled)
+ if !*mod.commonProperties.Enabled {
+ for oss, enabled := range osSupport {
+ if val := enabledProperty.SelectValue(bazel.OsConfigurationAxis, oss); enabled && val != nil && *val {
+ // if this should be disabled by default, clear out any enabling we've done
+ enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, oss, nil)
}
}
}
}
- if enabledPropertyOverrides.Value != nil {
- enabledProperty.Value = enabledPropertyOverrides.Value
+ required := depsToLabelList(mod.commonProperties.Required)
+ archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
+ for axis, configToProps := range archVariantProps {
+ for config, _props := range configToProps {
+ if archProps, ok := _props.(*commonProperties); ok {
+ // TODO(b/234748998) Remove this requiredFiltered workaround when aapt2 converts successfully
+ requiredFiltered := archProps.Required
+ if attrs.Name == "apexer" {
+ requiredFiltered = make([]string, 0, len(archProps.Required))
+ for _, req := range archProps.Required {
+ if req != "aapt2" && req != "apexer" {
+ requiredFiltered = append(requiredFiltered, req)
+ }
+ }
+ }
+ required.SetSelectValue(axis, config, depsToLabelList(requiredFiltered).Value)
+ if !neitherHostNorDevice {
+ if archProps.Enabled != nil {
+ if axis != bazel.OsConfigurationAxis || osSupport[config] {
+ enabledProperty.SetSelectValue(axis, config, archProps.Enabled)
+ }
+ }
+ }
+ }
+ }
}
- for _, axis := range enabledPropertyOverrides.SortedConfigurationAxes() {
- configToBools := enabledPropertyOverrides.ConfigurableValues[axis]
- for cfg, val := range configToBools {
- enabledProperty.SetSelectValue(axis, cfg, &val)
+
+ if !neitherHostNorDevice {
+ if enabledPropertyOverrides.Value != nil {
+ enabledProperty.Value = enabledPropertyOverrides.Value
+ }
+ for _, axis := range enabledPropertyOverrides.SortedConfigurationAxes() {
+ configToBools := enabledPropertyOverrides.ConfigurableValues[axis]
+ for cfg, val := range configToBools {
+ if axis != bazel.OsConfigurationAxis || osSupport[cfg] {
+ enabledProperty.SetSelectValue(axis, cfg, &val)
+ }
+ }
}
}
productConfigEnabledLabels := []bazel.Label{}
- if !proptools.BoolDefault(enabledProperty.Value, true) {
+ // TODO(b/234497586): Soong config variables and product variables have different overriding behavior, we
+ // should handle it correctly
+ if !proptools.BoolDefault(enabledProperty.Value, true) && !neitherHostNorDevice {
// If the module is not enabled by default, then we can check if a
// product variable enables it
productConfigEnabledLabels = productVariableConfigEnableLabels(ctx)
@@ -1224,27 +1267,27 @@
productConfigEnabledLabels, nil,
})
- moduleSupportsDevice := mod.commonProperties.HostOrDeviceSupported&deviceSupported == deviceSupported
- if mod.commonProperties.HostOrDeviceSupported != NeitherHostNorDeviceSupported && !moduleSupportsDevice {
- enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, Android.Name, proptools.BoolPtr(false))
- }
-
platformEnabledAttribute, err := enabledProperty.ToLabelListAttribute(
- bazel.LabelList{[]bazel.Label{bazel.Label{Label: "@platforms//:incompatible"}}, nil},
+ bazel.LabelList{[]bazel.Label{{Label: "@platforms//:incompatible"}}, nil},
bazel.LabelList{[]bazel.Label{}, nil})
if err != nil {
ctx.ModuleErrorf("Error processing platform enabled attribute: %s", err)
}
- data.Append(required)
+ // if android is the only arch/os enabled, then add a restriction to only be compatible with android
+ if platformEnabledAttribute.IsNil() && onlyAndroid {
+ l := bazel.LabelAttribute{}
+ l.SetValue(bazel.Label{Label: bazel.OsConfigurationAxis.SelectKey(Android.Name)})
+ platformEnabledAttribute.Add(&l)
+ }
- constraints := constraintAttributes{}
+ attrs.Data.Append(required)
+
moduleEnableConstraints := bazel.LabelListAttribute{}
moduleEnableConstraints.Append(platformEnabledAttribute)
moduleEnableConstraints.Append(productConfigEnabledAttribute)
- constraints.Target_compatible_with = moduleEnableConstraints
- return constraints
+ return constraintAttributes{Target_compatible_with: moduleEnableConstraints}
}
// Check product variables for `enabled: true` flag override.
@@ -1355,7 +1398,6 @@
checkbuildFiles Paths
packagingSpecs []PackagingSpec
packagingSpecsDepSet *packagingSpecsDepSet
- noticeFiles Paths
// katiInstalls tracks the install rules that were created by Soong but are being exported
// to Make to convert to ninja rules so that Make can add additional dependencies.
katiInstalls katiInstalls
@@ -1426,40 +1468,40 @@
}
func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) {
- m.commonProperties.Bp2buildInfo = append(m.commonProperties.Bp2buildInfo, info)
+ m.commonProperties.BazelConversionStatus.Bp2buildInfo = append(m.commonProperties.BazelConversionStatus.Bp2buildInfo, info)
}
// IsConvertedByBp2build returns whether this module was converted via bp2build.
func (m *ModuleBase) IsConvertedByBp2build() bool {
- return len(m.commonProperties.Bp2buildInfo) > 0
+ return len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0
}
// Bp2buildTargets returns the Bazel targets bp2build generated for this module.
func (m *ModuleBase) Bp2buildTargets() []bp2buildInfo {
- return m.commonProperties.Bp2buildInfo
+ return m.commonProperties.BazelConversionStatus.Bp2buildInfo
}
// AddUnconvertedBp2buildDep stores module name of a dependency that was not converted to Bazel.
func (b *baseModuleContext) AddUnconvertedBp2buildDep(dep string) {
- unconvertedDeps := &b.Module().base().commonProperties.UnconvertedBp2buildDeps
+ unconvertedDeps := &b.Module().base().commonProperties.BazelConversionStatus.UnconvertedDeps
*unconvertedDeps = append(*unconvertedDeps, dep)
}
// AddMissingBp2buildDep stores module name of a dependency that was not found in a Android.bp file.
func (b *baseModuleContext) AddMissingBp2buildDep(dep string) {
- missingDeps := &b.Module().base().commonProperties.MissingBp2buildDeps
+ missingDeps := &b.Module().base().commonProperties.BazelConversionStatus.MissingDeps
*missingDeps = append(*missingDeps, dep)
}
// GetUnconvertedBp2buildDeps returns the list of module names of this module's direct dependencies that
// were not converted to Bazel.
func (m *ModuleBase) GetUnconvertedBp2buildDeps() []string {
- return FirstUniqueStrings(m.commonProperties.UnconvertedBp2buildDeps)
+ return FirstUniqueStrings(m.commonProperties.BazelConversionStatus.UnconvertedDeps)
}
// GetMissingBp2buildDeps eturns the list of module names that were not found in Android.bp files.
func (m *ModuleBase) GetMissingBp2buildDeps() []string {
- return FirstUniqueStrings(m.commonProperties.MissingBp2buildDeps)
+ return FirstUniqueStrings(m.commonProperties.BazelConversionStatus.MissingDeps)
}
func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
@@ -1588,7 +1630,7 @@
// transformSourceToObj, and should only affects unit tests.
vars := m.VariablesForTests()
buildParams := append([]BuildParams(nil), m.buildParams...)
- for i, _ := range buildParams {
+ for i := range buildParams {
newArgs := make(map[string]string)
for k, v := range buildParams[i].Args {
newArgs[k] = v
@@ -1986,10 +2028,6 @@
return String(m.commonProperties.Owner)
}
-func (m *ModuleBase) NoticeFiles() Paths {
- return m.noticeFiles
-}
-
func (m *ModuleBase) setImageVariation(variant string) {
m.commonProperties.ImageVariation = variant
}
@@ -2237,7 +2275,7 @@
// Some common property checks for properties that will be used later in androidmk.go
checkDistProperties(ctx, "dist", &m.distProperties.Dist)
- for i, _ := range m.distProperties.Dists {
+ for i := range m.distProperties.Dists {
checkDistProperties(ctx, fmt.Sprintf("dists[%d]", i), &m.distProperties.Dists[i])
}
@@ -2249,27 +2287,6 @@
}
})
- m.noticeFiles = make([]Path, 0)
- optPath := OptionalPath{}
- notice := proptools.StringDefault(m.commonProperties.Notice, "")
- if module := SrcIsModule(notice); module != "" {
- optPath = ctx.ExpandOptionalSource(¬ice, "notice")
- } else if notice != "" {
- noticePath := filepath.Join(ctx.ModuleDir(), notice)
- optPath = ExistentPathForSource(ctx, noticePath)
- }
- if optPath.Valid() {
- m.noticeFiles = append(m.noticeFiles, optPath.Path())
- } else {
- for _, notice = range []string{"LICENSE", "LICENCE", "NOTICE"} {
- noticePath := filepath.Join(ctx.ModuleDir(), notice)
- optPath = ExistentPathForSource(ctx, noticePath)
- if optPath.Valid() {
- m.noticeFiles = append(m.noticeFiles, optPath.Path())
- }
- }
- }
-
licensesPropertyFlattener(ctx)
if ctx.Failed() {
return
@@ -3224,8 +3241,9 @@
extraCmds := ""
if extraZip != nil {
- extraCmds += fmt.Sprintf(" && unzip -qDD -d '%s' '%s'",
+ extraCmds += fmt.Sprintf(" && ( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} )",
extraZip.dir.String(), extraZip.zip.String())
+ extraCmds += " || ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )"
implicitDeps = append(implicitDeps, extraZip.zip)
}
@@ -3435,14 +3453,6 @@
return sourceOrOutputDependencyTag{moduleName: moduleName, tag: tag}
}
-// IsSourceDepTag returns true if the supplied blueprint.DependencyTag is one that was used to add
-// dependencies by either ExtractSourceDeps, ExtractSourcesDeps or automatically for properties
-// tagged with `android:"path"`.
-func IsSourceDepTag(depTag blueprint.DependencyTag) bool {
- _, ok := depTag.(sourceOrOutputDependencyTag)
- return ok
-}
-
// IsSourceDepTagWithOutputTag returns true if the supplied blueprint.DependencyTag is one that was
// used to add dependencies by either ExtractSourceDeps, ExtractSourcesDeps or automatically for
// properties tagged with `android:"path"` AND it was added using a module reference of
@@ -3569,14 +3579,14 @@
// be tagged with `android:"path" to support automatic source module dependency resolution.
//
// Deprecated: use PathForModuleSrc instead.
-func (m *moduleContext) ExpandSource(srcFile, prop string) Path {
+func (m *moduleContext) ExpandSource(srcFile, _ string) Path {
return PathForModuleSrc(m, srcFile)
}
// Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
// the srcFile is non-nil. The property must be tagged with `android:"path" to support automatic source module
// dependency resolution.
-func (m *moduleContext) ExpandOptionalSource(srcFile *string, prop string) OptionalPath {
+func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath {
if srcFile != nil {
return OptionalPathForPath(PathForModuleSrc(m, *srcFile))
}
diff --git a/android/mutator.go b/android/mutator.go
index f06ecda..9e4aa59 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -93,6 +93,7 @@
TopDown(name string, m TopDownMutator) MutatorHandle
BottomUp(name string, m BottomUpMutator) MutatorHandle
BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle
+ Transition(name string, m TransitionMutator)
}
type RegisterMutatorFunc func(RegisterMutatorsContext)
@@ -421,6 +422,182 @@
return mutator
}
+type IncomingTransitionContext interface {
+ // Module returns the target of the dependency edge for which the transition
+ // is being computed
+ Module() Module
+
+ // Config returns the configuration for the build.
+ Config() Config
+}
+
+type OutgoingTransitionContext interface {
+ // Module returns the target of the dependency edge for which the transition
+ // is being computed
+ Module() Module
+
+ // DepTag() Returns the dependency tag through which this dependency is
+ // reached
+ DepTag() blueprint.DependencyTag
+}
+
+// Transition mutators implement a top-down mechanism where a module tells its
+// direct dependencies what variation they should be built in but the dependency
+// has the final say.
+//
+// When implementing a transition mutator, one needs to implement four methods:
+// - Split() that tells what variations a module has by itself
+// - OutgoingTransition() where a module tells what it wants from its
+// dependency
+// - IncomingTransition() where a module has the final say about its own
+// variation
+// - Mutate() that changes the state of a module depending on its variation
+//
+// That the effective variation of module B when depended on by module A is the
+// composition the outgoing transition of module A and the incoming transition
+// of module B.
+//
+// the outgoing transition should not take the properties of the dependency into
+// account, only those of the module that depends on it. For this reason, the
+// dependency is not even passed into it as an argument. Likewise, the incoming
+// transition should not take the properties of the depending module into
+// account and is thus not informed about it. This makes for a nice
+// decomposition of the decision logic.
+//
+// A given transition mutator only affects its own variation; other variations
+// stay unchanged along the dependency edges.
+//
+// Soong makes sure that all modules are created in the desired variations and
+// that dependency edges are set up correctly. This ensures that "missing
+// variation" errors do not happen and allows for more flexible changes in the
+// value of the variation among dependency edges (as oppposed to bottom-up
+// mutators where if module A in variation X depends on module B and module B
+// has that variation X, A must depend on variation X of B)
+//
+// The limited power of the context objects passed to individual mutators
+// methods also makes it more difficult to shoot oneself in the foot. Complete
+// safety is not guaranteed because no one prevents individual transition
+// mutators from mutating modules in illegal ways and for e.g. Split() or
+// Mutate() to run their own visitations of the transitive dependency of the
+// module and both of these are bad ideas, but it's better than no guardrails at
+// all.
+//
+// This model is pretty close to Bazel's configuration transitions. The mapping
+// between concepts in Soong and Bazel is as follows:
+// - Module == configured target
+// - Variant == configuration
+// - Variation name == configuration flag
+// - Variation == configuration flag value
+// - Outgoing transition == attribute transition
+// - Incoming transition == rule transition
+//
+// The Split() method does not have a Bazel equivalent and Bazel split
+// transitions do not have a Soong equivalent.
+//
+// Mutate() does not make sense in Bazel due to the different models of the
+// two systems: when creating new variations, Soong clones the old module and
+// thus some way is needed to change it state whereas Bazel creates each
+// configuration of a given configured target anew.
+type TransitionMutator interface {
+ // Split returns the set of variations that should be created for a module no
+ // matter who depends on it. Used when Make depends on a particular variation
+ // or when the module knows its variations just based on information given to
+ // it in the Blueprint file. This method should not mutate the module it is
+ // called on.
+ Split(ctx BaseModuleContext) []string
+
+ // Called on a module to determine which variation it wants from its direct
+ // dependencies. The dependency itself can override this decision. This method
+ // should not mutate the module itself.
+ OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
+
+ // Called on a module to determine which variation it should be in based on
+ // the variation modules that depend on it want. This gives the module a final
+ // say about its own variations. This method should not mutate the module
+ // itself.
+ IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string
+
+ // Called after a module was split into multiple variations on each variation.
+ // It should not split the module any further but adding new dependencies is
+ // fine. Unlike all the other methods on TransitionMutator, this method is
+ // allowed to mutate the module.
+ Mutate(ctx BottomUpMutatorContext, variation string)
+}
+
+type androidTransitionMutator struct {
+ finalPhase bool
+ bazelConversionMode bool
+ mutator TransitionMutator
+}
+
+func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string {
+ if m, ok := ctx.Module().(Module); ok {
+ moduleContext := m.base().baseModuleContextFactory(ctx)
+ moduleContext.bazelConversionMode = a.bazelConversionMode
+ return a.mutator.Split(&moduleContext)
+ } else {
+ return []string{""}
+ }
+}
+
+type outgoingTransitionContextImpl struct {
+ bp blueprint.OutgoingTransitionContext
+}
+
+func (c *outgoingTransitionContextImpl) Module() Module {
+ return c.bp.Module().(Module)
+}
+
+func (c *outgoingTransitionContextImpl) DepTag() blueprint.DependencyTag {
+ return c.bp.DepTag()
+}
+
+func (a *androidTransitionMutator) OutgoingTransition(ctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
+ if _, ok := ctx.Module().(Module); ok {
+ return a.mutator.OutgoingTransition(&outgoingTransitionContextImpl{bp: ctx}, sourceVariation)
+ } else {
+ return ""
+ }
+}
+
+type incomingTransitionContextImpl struct {
+ bp blueprint.IncomingTransitionContext
+}
+
+func (c *incomingTransitionContextImpl) Module() Module {
+ return c.bp.Module().(Module)
+}
+
+func (c *incomingTransitionContextImpl) Config() Config {
+ return c.bp.Config().(Config)
+}
+
+func (a *androidTransitionMutator) IncomingTransition(ctx blueprint.IncomingTransitionContext, incomingVariation string) string {
+ if _, ok := ctx.Module().(Module); ok {
+ return a.mutator.IncomingTransition(&incomingTransitionContextImpl{bp: ctx}, incomingVariation)
+ } else {
+ return ""
+ }
+}
+
+func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) {
+ if am, ok := ctx.Module().(Module); ok {
+ a.mutator.Mutate(bottomUpMutatorContextFactory(ctx, am, a.finalPhase, a.bazelConversionMode), variation)
+ }
+}
+
+func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) {
+ atm := &androidTransitionMutator{
+ finalPhase: x.finalPhase,
+ bazelConversionMode: x.bazelConversionMode,
+ mutator: m,
+ }
+ mutator := &mutator{
+ name: name,
+ transitionMutator: atm}
+ x.mutators = append(x.mutators, mutator)
+}
+
func (x *registerMutatorsContext) mutatorName(name string) string {
if x.bazelConversionMode {
return name + "_bp2build"
@@ -456,6 +633,8 @@
handle = blueprintCtx.RegisterBottomUpMutator(mutator.name, mutator.bottomUpMutator)
} else if mutator.topDownMutator != nil {
handle = blueprintCtx.RegisterTopDownMutator(mutator.name, mutator.topDownMutator)
+ } else if mutator.transitionMutator != nil {
+ blueprintCtx.RegisterTransitionMutator(mutator.name, mutator.transitionMutator)
}
if mutator.parallel {
handle.Parallel()
diff --git a/android/neverallow.go b/android/neverallow.go
index aa47bca..00078a0 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -212,11 +212,16 @@
}
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$")).
- Because("Only boot images may be imported as a makefile goal."),
+ NotIn(allowlist...).
+ Because("Only boot images may be imported as a makefile goal if not in allowed projects"),
}
}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 86f1a37..4772799 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -324,7 +324,32 @@
`),
},
expectedErrors: []string{
- "Only boot images may be imported as a makefile goal.",
+ "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
diff --git a/android/notices.go b/android/notices.go
index 562a156..b9c1682 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -47,7 +47,9 @@
}
// buildNoticeOutputFromLicenseMetadata writes out a notice file.
-func buildNoticeOutputFromLicenseMetadata(ctx BuilderContext, tool, ruleName string, outputFile WritablePath, libraryName, stripPrefix string, modules ...Module) {
+func buildNoticeOutputFromLicenseMetadata(
+ ctx BuilderContext, tool, ruleName string, outputFile WritablePath,
+ libraryName string, stripPrefix []string, modules ...Module) {
depsFile := outputFile.ReplaceExtension(ctx, strings.TrimPrefix(outputFile.Ext()+".d", "."))
rule := NewRuleBuilder(pctx, ctx)
if len(modules) == 0 {
@@ -64,8 +66,8 @@
BuiltTool(tool).
FlagWithOutput("-o ", outputFile).
FlagWithDepFile("-d ", depsFile)
- if stripPrefix != "" {
- cmd = cmd.FlagWithArg("--strip_prefix ", stripPrefix)
+ if len(stripPrefix) > 0 {
+ cmd = cmd.FlagForEachArg("--strip_prefix ", stripPrefix)
}
outputs := modulesOutputDirs(ctx, modules...)
if len(outputs) > 0 {
@@ -81,20 +83,29 @@
// BuildNoticeTextOutputFromLicenseMetadata writes out a notice text file based
// on the license metadata files for the input `modules` defaulting to the
// current context module if none given.
-func BuildNoticeTextOutputFromLicenseMetadata(ctx BuilderContext, outputFile WritablePath, ruleName, libraryName, stripPrefix string, modules ...Module) {
- buildNoticeOutputFromLicenseMetadata(ctx, "textnotice", "text_notice_"+ruleName, outputFile, libraryName, stripPrefix, modules...)
+func BuildNoticeTextOutputFromLicenseMetadata(
+ ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
+ stripPrefix []string, modules ...Module) {
+ buildNoticeOutputFromLicenseMetadata(ctx, "textnotice", "text_notice_"+ruleName,
+ outputFile, libraryName, stripPrefix, modules...)
}
// BuildNoticeHtmlOutputFromLicenseMetadata writes out a notice text file based
// on the license metadata files for the input `modules` defaulting to the
// current context module if none given.
-func BuildNoticeHtmlOutputFromLicenseMetadata(ctx BuilderContext, outputFile WritablePath, ruleName, libraryName, stripPrefix string, modules ...Module) {
- buildNoticeOutputFromLicenseMetadata(ctx, "htmlnotice", "html_notice_"+ruleName, outputFile, libraryName, stripPrefix, modules...)
+func BuildNoticeHtmlOutputFromLicenseMetadata(
+ ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
+ stripPrefix []string, modules ...Module) {
+ buildNoticeOutputFromLicenseMetadata(ctx, "htmlnotice", "html_notice_"+ruleName,
+ outputFile, libraryName, stripPrefix, modules...)
}
// BuildNoticeXmlOutputFromLicenseMetadata writes out a notice text file based
// on the license metadata files for the input `modules` defaulting to the
// current context module if none given.
-func BuildNoticeXmlOutputFromLicenseMetadata(ctx BuilderContext, outputFile WritablePath, ruleName, libraryName, stripPrefix string, modules ...Module) {
- buildNoticeOutputFromLicenseMetadata(ctx, "xmlnotice", "xml_notice_"+ruleName, outputFile, libraryName, stripPrefix, modules...)
+func BuildNoticeXmlOutputFromLicenseMetadata(
+ ctx BuilderContext, outputFile WritablePath, ruleName, libraryName string,
+ stripPrefix []string, modules ...Module) {
+ buildNoticeOutputFromLicenseMetadata(ctx, "xmlnotice", "xml_notice_"+ruleName,
+ outputFile, libraryName, stripPrefix, modules...)
}
diff --git a/android/onceper.go b/android/onceper.go
index 481cdea..fa415d1 100644
--- a/android/onceper.go
+++ b/android/onceper.go
@@ -79,6 +79,17 @@
return once.maybeWaitFor(key, v)
}
+// Peek returns the value previously computed with Once for a given key. If Once has not
+// been called for the given key Peek will return ok == false.
+func (once *OncePer) Peek(key OnceKey) (interface{}, bool) {
+ v, ok := once.values.Load(key)
+ if !ok {
+ return nil, false
+ }
+
+ return once.maybeWaitFor(key, v), true
+}
+
// OnceStringSlice is the same as Once, but returns the value cast to a []string
func (once *OncePer) OnceStringSlice(key OnceKey, value func() []string) []string {
return once.Once(key, func() interface{} { return value() }).([]string)
diff --git a/android/paths.go b/android/paths.go
index e0e5ae5..f8e7018 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1474,7 +1474,7 @@
// PathForVndkRefAbiDump returns an OptionalPath representing the path of the
// reference abi dump for the given module. This is not guaranteed to be valid.
func PathForVndkRefAbiDump(ctx ModuleInstallPathContext, version, fileName string,
- isNdk, isLlndkOrVndk, isGzip bool) OptionalPath {
+ isNdk, isVndk, isGzip bool) OptionalPath {
currentArchType := ctx.Arch().ArchType
primaryArchType := ctx.Config().DevicePrimaryArchType()
@@ -1486,7 +1486,7 @@
var dirName string
if isNdk {
dirName = "ndk"
- } else if isLlndkOrVndk {
+ } else if isVndk {
dirName = "vndk"
} else {
dirName = "platform" // opt-in libs
@@ -1739,10 +1739,16 @@
partionPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
} else {
osName := os.String()
- if os == Linux || os == LinuxMusl {
+ if os == Linux {
// instead of linux_glibc
osName = "linux"
}
+ if os == LinuxMusl && ctx.Config().UseHostMusl() {
+ // When using musl instead of glibc, use "linux" instead of "linux_musl". When cross
+ // compiling we will still use "linux_musl".
+ osName = "linux"
+ }
+
// SOONG_HOST_OUT is set to out/host/$(HOST_OS)-$(HOST_PREBUILT_ARCH)
// and HOST_PREBUILT_ARCH is forcibly set to x86 even on x86_64 hosts. We don't seem
// to have a plan to fix it (see the comment in build/make/core/envsetup.mk).
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 5843487..4e4fa42 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -110,6 +110,18 @@
return strings.TrimPrefix(name, "prebuilt_")
}
+// RemoveOptionalPrebuiltPrefixFromBazelLabel removes the "prebuilt_" prefix from the *target name* of a Bazel label.
+// This differs from RemoveOptionalPrebuiltPrefix in that it does not remove it from the start of the string, but
+// instead removes it from the target name itself.
+func RemoveOptionalPrebuiltPrefixFromBazelLabel(label string) string {
+ splitLabel := strings.Split(label, ":")
+ bazelModuleNameNoPrebuilt := RemoveOptionalPrebuiltPrefix(splitLabel[1])
+ return strings.Join([]string{
+ splitLabel[0],
+ bazelModuleNameNoPrebuilt,
+ }, ":")
+}
+
func (p *Prebuilt) Name(name string) string {
return PrebuiltNameFromSource(name)
}
diff --git a/android/register.go b/android/register.go
index c505833..4ff8fff 100644
--- a/android/register.go
+++ b/android/register.go
@@ -96,10 +96,11 @@
var preSingletons sortableComponents
type mutator struct {
- name string
- bottomUpMutator blueprint.BottomUpMutator
- topDownMutator blueprint.TopDownMutator
- parallel bool
+ name string
+ bottomUpMutator blueprint.BottomUpMutator
+ topDownMutator blueprint.TopDownMutator
+ transitionMutator blueprint.TransitionMutator
+ parallel bool
}
var _ sortableComponent = &mutator{}
diff --git a/android/sdk.go b/android/sdk.go
index 2dc0bd7..a71f7f2 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -661,6 +661,10 @@
// an Android.bp file.
RequiresBpProperty() bool
+ // SupportedBuildReleases returns the string representation of a set of target build releases that
+ // support this member type.
+ SupportedBuildReleases() string
+
// UsableWithSdkAndSdkSnapshot returns true if the member type supports the sdk/sdk_snapshot,
// false otherwise.
UsableWithSdkAndSdkSnapshot() bool
@@ -673,6 +677,10 @@
// SupportedLinkages returns the names of the linkage variants supported by this module.
SupportedLinkages() []string
+ // ArePrebuiltsRequired returns true if prebuilts are required in the sdk snapshot, false
+ // otherwise.
+ ArePrebuiltsRequired() bool
+
// AddDependencies adds dependencies from the SDK module to all the module variants the member
// type contributes to the SDK. `names` is the list of module names given in the member type
// property (as returned by SdkPropertyName()) in the SDK module. The exact set of variants
@@ -773,7 +781,17 @@
// property to be specifiable in an Android.bp file.
BpPropertyNotRequired bool
- SupportsSdk bool
+ // The name of the first targeted build release.
+ //
+ // If not specified then it is assumed to be available on all targeted build releases.
+ SupportedBuildReleaseSpecification string
+
+ // Set to true if this must be usable with the sdk/sdk_snapshot module types. Otherwise, it will
+ // only be usable with module_exports/module_exports_snapshots module types.
+ SupportsSdk bool
+
+ // Set to true if prebuilt host artifacts of this member may be specific to the host OS. Only
+ // applicable to modules where HostSupported() is true.
HostOsDependent bool
// When set to true UseSourceModuleTypeInSnapshot indicates that the member type creates a source
@@ -781,6 +799,11 @@
// code from automatically adding a prefer: true flag.
UseSourceModuleTypeInSnapshot bool
+ // Set to proptools.BoolPtr(false) if this member does not generate prebuilts but is only provided
+ // to allow the sdk to gather members from this member's dependencies. If not specified then
+ // defaults to true.
+ PrebuiltsRequired *bool
+
// The list of supported traits.
Traits []SdkMemberTrait
}
@@ -793,6 +816,10 @@
return !b.BpPropertyNotRequired
}
+func (b *SdkMemberTypeBase) SupportedBuildReleases() string {
+ return b.SupportedBuildReleaseSpecification
+}
+
func (b *SdkMemberTypeBase) UsableWithSdkAndSdkSnapshot() bool {
return b.SupportsSdk
}
@@ -801,6 +828,10 @@
return b.HostOsDependent
}
+func (b *SdkMemberTypeBase) ArePrebuiltsRequired() bool {
+ return proptools.BoolDefault(b.PrebuiltsRequired, true)
+}
+
func (b *SdkMemberTypeBase) UsesSourceModuleTypeInSnapshot() bool {
return b.UseSourceModuleTypeInSnapshot
}
@@ -954,6 +985,10 @@
// RequiresTrait returns true if this member is expected to provide the specified trait.
RequiresTrait(trait SdkMemberTrait) bool
+
+ // IsTargetBuildBeforeTiramisu return true if the target build release for which this snapshot is
+ // being generated is before Tiramisu, i.e. S.
+ IsTargetBuildBeforeTiramisu() bool
}
// ExportedComponentsInfo contains information about the components that this module exports to an
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 2004c92..c188c48 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -28,6 +28,9 @@
// MinSdkVersion returns SdkSpec that corresponds to the min_sdk_version property of the current module,
// or from sdk_version if it is not set.
MinSdkVersion(ctx EarlyModuleContext) SdkSpec
+ // ReplaceMaxSdkVersionPlaceholder returns SdkSpec to replace the maxSdkVersion property of permission and
+ // uses-permission tags if it is set.
+ ReplaceMaxSdkVersionPlaceholder(ctx EarlyModuleContext) SdkSpec
// TargetSdkVersion returns the SdkSpec that corresponds to the target_sdk_version property of the current module,
// or from sdk_version if it is not set.
TargetSdkVersion(ctx EarlyModuleContext) SdkSpec
diff --git a/android/test_config.go b/android/test_config.go
new file mode 100644
index 0000000..f36e8ba
--- /dev/null
+++ b/android/test_config.go
@@ -0,0 +1,145 @@
+// 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 android
+
+import (
+ "encoding/json"
+ "os"
+ "path/filepath"
+ "runtime"
+
+ "github.com/google/blueprint/proptools"
+)
+
+// TestConfig returns a Config object for testing.
+func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
+ envCopy := make(map[string]string)
+ for k, v := range env {
+ envCopy[k] = v
+ }
+
+ // Copy the real PATH value to the test environment, it's needed by
+ // NonHermeticHostSystemTool() used in x86_darwin_host.go
+ envCopy["PATH"] = os.Getenv("PATH")
+
+ config := &config{
+ productVariables: productVariables{
+ DeviceName: stringPtr("test_device"),
+ DeviceProduct: stringPtr("test_product"),
+ Platform_sdk_version: intPtr(30),
+ Platform_sdk_codename: stringPtr("S"),
+ Platform_base_sdk_extension_version: intPtr(1),
+ Platform_version_active_codenames: []string{"S", "Tiramisu"},
+ DeviceSystemSdkVersions: []string{"14", "15"},
+ Platform_systemsdk_versions: []string{"29", "30"},
+ AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
+ AAPTPreferredConfig: stringPtr("xhdpi"),
+ AAPTCharacteristics: stringPtr("nosdcard"),
+ AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"},
+ UncompressPrivAppDex: boolPtr(true),
+ ShippingApiLevel: stringPtr("30"),
+ },
+
+ outDir: buildDir,
+ soongOutDir: filepath.Join(buildDir, "soong"),
+ captureBuild: true,
+ env: envCopy,
+
+ // Set testAllowNonExistentPaths so that test contexts don't need to specify every path
+ // passed to PathForSource or PathForModuleSrc.
+ TestAllowNonExistentPaths: true,
+
+ BazelContext: noopBazelContext{},
+ mixedBuildDisabledModules: make(map[string]struct{}),
+ mixedBuildEnabledModules: make(map[string]struct{}),
+ }
+ config.deviceConfig = &deviceConfig{
+ config: config,
+ }
+ config.TestProductVariables = &config.productVariables
+
+ config.mockFileSystem(bp, fs)
+
+ determineBuildOS(config)
+
+ return Config{config}
+}
+
+func modifyTestConfigToSupportArchMutator(testConfig Config) {
+ config := testConfig.config
+
+ config.Targets = map[OsType][]Target{
+ Android: []Target{
+ {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false},
+ {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false},
+ },
+ config.BuildOS: []Target{
+ {config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
+ {config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
+ },
+ }
+
+ if runtime.GOOS == "darwin" {
+ config.Targets[config.BuildOS] = config.Targets[config.BuildOS][:1]
+ }
+
+ config.BuildOSTarget = config.Targets[config.BuildOS][0]
+ config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
+ config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
+ config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
+ config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
+ config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
+ config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
+ config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon")
+}
+
+func modifyTestConfigForMusl(config Config) {
+ delete(config.Targets, config.BuildOS)
+ config.productVariables.HostMusl = boolPtr(true)
+ determineBuildOS(config.config)
+ config.Targets[config.BuildOS] = []Target{
+ {config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
+ {config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
+ }
+
+ config.BuildOSTarget = config.Targets[config.BuildOS][0]
+ config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
+}
+
+// TestArchConfig returns a Config object suitable for using for tests that
+// need to run the arch mutator.
+func TestArchConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
+ testConfig := TestConfig(buildDir, env, bp, fs)
+ modifyTestConfigToSupportArchMutator(testConfig)
+ return testConfig
+}
+
+// CreateTestConfiguredJarList is a function to create ConfiguredJarList for tests.
+func CreateTestConfiguredJarList(list []string) ConfiguredJarList {
+ // Create the ConfiguredJarList in as similar way as it is created at runtime by marshalling to
+ // a json list of strings and then unmarshalling into a ConfiguredJarList instance.
+ b, err := json.Marshal(list)
+ if err != nil {
+ panic(err)
+ }
+
+ var jarList ConfiguredJarList
+ err = json.Unmarshal(b, &jarList)
+ if err != nil {
+ panic(err)
+ }
+
+ return jarList
+}
diff --git a/android/updatable_modules.go b/android/updatable_modules.go
new file mode 100644
index 0000000..71c76c5
--- /dev/null
+++ b/android/updatable_modules.go
@@ -0,0 +1,36 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+// This file contains branch specific constants for building updatable modules.
+// They are stored in a separate file to minimise the potential of merge
+// conflicts between branches when the code from the package is changed.
+
+// The default manifest version for all the modules on this branch.
+// This version code will be used only if there is no version field in the
+// module's apex_manifest.json. Release branches have their version injected
+// into apex_manifest.json by the tooling and will not use the version set
+// here. Developers can also set the version field locally in the
+// apex_manifest.json to build a module with a specific version.
+//
+// The value follows the schema from go/mainline-version-codes, and is chosen
+// based on the branch such that the builds from testing and development
+// branches will have a version higher than the prebuilts.
+// Versions per branch:
+// * x-dev - xx0090000 (where xx is the branch SDK level)
+// * AOSP - xx9990000
+// * x-mainline-prod - xx9990000
+// * master - 990090000
+const DefaultUpdatableModuleVersion = "339990000"
diff --git a/android/util.go b/android/util.go
index 47c4583..a0f7160 100644
--- a/android/util.go
+++ b/android/util.go
@@ -32,6 +32,12 @@
// JoinWithPrefix prepends the prefix to each string in the list and
// returns them joined together with " " as separator.
func JoinWithPrefix(strs []string, prefix string) string {
+ return JoinWithPrefixAndSeparator(strs, prefix, " ")
+}
+
+// JoinWithPrefixAndSeparator prepends the prefix to each string in the list and
+// returns them joined together with the given separator.
+func JoinWithPrefixAndSeparator(strs []string, prefix string, sep string) string {
if len(strs) == 0 {
return ""
}
@@ -40,7 +46,7 @@
buf.WriteString(prefix)
buf.WriteString(strs[0])
for i := 1; i < len(strs); i++ {
- buf.WriteString(" ")
+ buf.WriteString(sep)
buf.WriteString(prefix)
buf.WriteString(strs[i])
}
diff --git a/android/variable.go b/android/variable.go
index 9478c0c..86b8c8f 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -200,6 +200,7 @@
Platform_min_supported_target_sdk_version *string `json:",omitempty"`
Platform_base_os *string `json:",omitempty"`
Platform_version_last_stable *string `json:",omitempty"`
+ Platform_version_known_codenames *string `json:",omitempty"`
DeviceName *string `json:",omitempty"`
DeviceProduct *string `json:",omitempty"`
@@ -248,7 +249,8 @@
AAPTPreferredConfig *string `json:",omitempty"`
AAPTPrebuiltDPI []string `json:",omitempty"`
- DefaultAppCertificate *string `json:",omitempty"`
+ DefaultAppCertificate *string `json:",omitempty"`
+ MainlineSepolicyDevCertificates *string `json:",omitempty"`
AppsDefaultVersionName *string `json:",omitempty"`
@@ -428,6 +430,7 @@
ShippingApiLevel *string `json:",omitempty"`
+ BuildBrokenDepfile *bool `json:",omitempty"`
BuildBrokenEnforceSyspropOwner bool `json:",omitempty"`
BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"`
BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
@@ -445,6 +448,8 @@
SepolicyFreezeTestExtraPrebuiltDirs []string `json:",omitempty"`
GenerateAidlNdkPlatformBackend bool `json:",omitempty"`
+
+ IgnorePrefer32OnDevice bool `json:",omitempty"`
}
func boolPtr(v bool) *bool {
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index 9519be0..f646742 100644
--- a/android_sdk/sdk_repo_host.go
+++ b/android_sdk/sdk_repo_host.go
@@ -124,7 +124,12 @@
s.CopySpecsToDir(ctx, builder, packageSpecs, dir)
noticeFile := android.PathForModuleOut(ctx, "NOTICES.txt")
- android.BuildNoticeTextOutputFromLicenseMetadata(ctx, noticeFile, "", "", outputZipFile.String())
+ android.BuildNoticeTextOutputFromLicenseMetadata(
+ ctx, noticeFile, "", "",
+ []string{
+ android.PathForModuleInstall(ctx, "sdk-repo").String() + "/",
+ outputZipFile.String(),
+ })
builder.Command().Text("cp").
Input(noticeFile).
Text(filepath.Join(dir.String(), "NOTICE.txt"))
@@ -161,9 +166,10 @@
}
} else {
llvmStrip := config.ClangPath(ctx, "bin/llvm-strip")
- llvmLib := config.ClangPath(ctx, "lib64/libc++.so.1")
+ llvmLib64 := config.ClangPath(ctx, "lib64/libc++.so.1")
+ llvmLib := config.ClangPath(ctx, "lib/libc++.so.1")
for _, strip := range s.properties.Strip_files {
- cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib)
+ cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib64).ImplicitTool(llvmLib)
if !ctx.Windows() {
cmd.Flag("-x")
}
diff --git a/apex/Android.bp b/apex/Android.bp
index d3417c2..018d030 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -23,8 +23,10 @@
srcs: [
"androidmk.go",
"apex.go",
+ "apex_sdk_member.go",
"apex_singleton.go",
"builder.go",
+ "bp2build.go",
"deapexer.go",
"key.go",
"prebuilt.go",
diff --git a/apex/androidmk.go b/apex/androidmk.go
index e094a12..3373211 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -168,10 +168,6 @@
if len(newDataPaths) > 0 {
fmt.Fprintln(w, "LOCAL_TEST_DATA :=", strings.Join(android.AndroidMkDataPaths(newDataPaths), " "))
}
-
- if fi.module != nil && len(fi.module.NoticeFiles()) > 0 {
- fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", strings.Join(fi.module.NoticeFiles().Strings(), " "))
- }
} else {
modulePath = pathWhenActivated
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", pathWhenActivated)
@@ -412,6 +408,7 @@
fmt.Fprintln(w, ".PHONY:", goal)
fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
goal, a.installedFilesFile.String(), distFile)
+ fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", a.installedFilesFile.String())
}
for _, dist := range data.Entries.GetDistForGoals(a) {
fmt.Fprintf(w, dist)
diff --git a/apex/apex.go b/apex/apex.go
index 21725ff..b391a6c 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -17,6 +17,7 @@
package apex
import (
+ "android/soong/bazel/cquery"
"fmt"
"path/filepath"
"regexp"
@@ -606,6 +607,18 @@
// replacement. This is needed because some prebuilt modules do not provide all the information
// needed by the apex.
sourceOnly bool
+
+ // If not-nil and an APEX is a member of an SDK then dependencies of that APEX with this tag will
+ // also be added as exported members of that SDK.
+ memberType android.SdkMemberType
+}
+
+func (d *dependencyTag) SdkMemberType(_ android.Module) android.SdkMemberType {
+ return d.memberType
+}
+
+func (d *dependencyTag) ExportMember() bool {
+ return true
}
func (d *dependencyTag) String() string {
@@ -617,6 +630,7 @@
}
var _ android.ReplaceSourceWithPrebuilt = &dependencyTag{}
+var _ android.SdkMemberDependencyTag = &dependencyTag{}
var (
androidAppTag = &dependencyTag{name: "androidApp", payload: true}
@@ -624,9 +638,9 @@
certificateTag = &dependencyTag{name: "certificate"}
executableTag = &dependencyTag{name: "executable", payload: true}
fsTag = &dependencyTag{name: "filesystem", payload: true}
- bcpfTag = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true}
- sscpfTag = &dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true}
- compatConfigTag = &dependencyTag{name: "compatConfig", payload: true, sourceOnly: true}
+ bcpfTag = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true, memberType: java.BootclasspathFragmentSdkMemberType}
+ sscpfTag = &dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true, memberType: java.SystemServerClasspathFragmentSdkMemberType}
+ compatConfigTag = &dependencyTag{name: "compatConfig", payload: true, sourceOnly: true, memberType: java.CompatConfigSdkMemberType}
javaLibTag = &dependencyTag{name: "javaLib", payload: true}
jniLibTag = &dependencyTag{name: "jniLib", payload: true}
keyTag = &dependencyTag{name: "key"}
@@ -1338,7 +1352,7 @@
var _ android.DepIsInSameApex = (*apexBundle)(nil)
// Implements android.DepInInSameApex
-func (a *apexBundle) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+func (a *apexBundle) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
// direct deps of an APEX bundle are all part of the APEX bundle
// TODO(jiyong): shouldn't we look into the payload field of the dependencyTag?
return true
@@ -1468,19 +1482,19 @@
}
}
-func (a *apexBundle) IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool {
+func (a *apexBundle) IsSanitizerEnabled(config android.Config, sanitizerName string) bool {
if android.InList(sanitizerName, a.properties.SanitizerNames) {
return true
}
// Then follow the global setting
- globalSanitizerNames := []string{}
+ var globalSanitizerNames []string
if a.Host() {
- globalSanitizerNames = ctx.Config().SanitizeHost()
+ globalSanitizerNames = config.SanitizeHost()
} else {
- arches := ctx.Config().SanitizeDeviceArch()
+ arches := config.SanitizeDeviceArch()
if len(arches) == 0 || android.InList(a.Arch().ArchType.Name, arches) {
- globalSanitizerNames = ctx.Config().SanitizeDevice()
+ globalSanitizerNames = config.SanitizeDevice()
}
}
return android.InList(sanitizerName, globalSanitizerNames)
@@ -1790,409 +1804,136 @@
}
}
-// Creates build rules for an APEX. It consists of the following major steps:
-//
-// 1) do some validity checks such as apex_available, min_sdk_version, etc.
-// 2) traverse the dependency tree to collect apexFile structs from them.
-// 3) some fields in apexBundle struct are configured
-// 4) generate the build rules to create the APEX. This is mostly done in builder.go.
-func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- ////////////////////////////////////////////////////////////////////////////////////////////
- // 1) do some validity checks such as apex_available, min_sdk_version, etc.
- a.checkApexAvailability(ctx)
- a.checkUpdatable(ctx)
- a.CheckMinSdkVersion(ctx)
- a.checkStaticLinkingToStubLibraries(ctx)
- a.checkStaticExecutables(ctx)
- if len(a.properties.Tests) > 0 && !a.testApex {
- ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
+var _ android.MixedBuildBuildable = (*apexBundle)(nil)
+
+func (a *apexBundle) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
+ return ctx.ModuleType() == "apex" && a.properties.ApexType == imageApex
+}
+
+func (a *apexBundle) QueueBazelCall(ctx android.BaseModuleContext) {
+ bazelCtx := ctx.Config().BazelContext
+ bazelCtx.QueueBazelRequest(a.GetBazelLabel(ctx, a), cquery.GetApexInfo, android.GetConfigKey(ctx))
+}
+
+func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) {
+ if !a.commonBuildActions(ctx) {
return
}
- ////////////////////////////////////////////////////////////////////////////////////////////
- // 2) traverse the dependency tree to collect apexFile structs from them.
+ a.setApexTypeAndSuffix(ctx)
+ a.setPayloadFsType(ctx)
+ a.setSystemLibLink(ctx)
- // all the files that will be included in this APEX
- var filesInfo []apexFile
+ if a.properties.ApexType != zipApex {
+ a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
+ }
- // native lib dependencies
- var provideNativeLibs []string
- var requireNativeLibs []string
-
- handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
-
- // Collect the module directory for IDE info in java/jdeps.go.
- a.modulePaths = append(a.modulePaths, ctx.ModuleDir())
-
- // TODO(jiyong): do this using WalkPayloadDeps
- // TODO(jiyong): make this clean!!!
- ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
- depTag := ctx.OtherModuleDependencyTag(child)
- if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
- return false
- }
- if mod, ok := child.(android.Module); ok && !mod.Enabled() {
- return false
- }
- depName := ctx.OtherModuleName(child)
- if _, isDirectDep := parent.(*apexBundle); isDirectDep {
- switch depTag {
- case sharedLibTag, jniLibTag:
- isJniLib := depTag == jniLibTag
- if c, ok := child.(*cc.Module); ok {
- fi := apexFileForNativeLibrary(ctx, c, handleSpecialLibs)
- fi.isJniLib = isJniLib
- filesInfo = append(filesInfo, fi)
- // Collect the list of stub-providing libs except:
- // - VNDK libs are only for vendors
- // - bootstrap bionic libs are treated as provided by system
- if c.HasStubsVariants() && !a.vndkApex && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
- provideNativeLibs = append(provideNativeLibs, fi.stem())
- }
- return true // track transitive dependencies
- } else if r, ok := child.(*rust.Module); ok {
- fi := apexFileForRustLibrary(ctx, r)
- fi.isJniLib = isJniLib
- filesInfo = append(filesInfo, fi)
- return true // track transitive dependencies
- } else {
- propertyName := "native_shared_libs"
- if isJniLib {
- propertyName = "jni_libs"
- }
- ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
- }
- case executableTag:
- if cc, ok := child.(*cc.Module); ok {
- filesInfo = append(filesInfo, apexFileForExecutable(ctx, cc))
- return true // track transitive dependencies
- } else if py, ok := child.(*python.Module); ok && py.HostToolPath().Valid() {
- filesInfo = append(filesInfo, apexFileForPyBinary(ctx, py))
- } else if gb, ok := child.(bootstrap.GoBinaryTool); ok && a.Host() {
- filesInfo = append(filesInfo, apexFileForGoBinary(ctx, depName, gb))
- } else if rust, ok := child.(*rust.Module); ok {
- filesInfo = append(filesInfo, apexFileForRustExecutable(ctx, rust))
- return true // track transitive dependencies
- } else {
- ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, nor (host) bootstrap_go_binary", depName)
- }
- case shBinaryTag:
- if sh, ok := child.(*sh.ShBinary); ok {
- filesInfo = append(filesInfo, apexFileForShBinary(ctx, sh))
- } else {
- ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName)
- }
- case bcpfTag:
- {
- bcpfModule, ok := child.(*java.BootclasspathFragmentModule)
- if !ok {
- ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a bootclasspath_fragment module", depName)
- return false
- }
-
- filesToAdd := apexBootclasspathFragmentFiles(ctx, child)
- filesInfo = append(filesInfo, filesToAdd...)
- for _, makeModuleName := range bcpfModule.BootImageDeviceInstallMakeModules() {
- a.requiredDeps = append(a.requiredDeps, makeModuleName)
- }
- return true
- }
- case sscpfTag:
- {
- if _, ok := child.(*java.SystemServerClasspathModule); !ok {
- ctx.PropertyErrorf("systemserverclasspath_fragments", "%q is not a systemserverclasspath_fragment module", depName)
- return false
- }
- if af := apexClasspathFragmentProtoFile(ctx, child); af != nil {
- filesInfo = append(filesInfo, *af)
- }
- return true
- }
- case javaLibTag:
- switch child.(type) {
- case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import:
- af := apexFileForJavaModule(ctx, child.(javaModule))
- if !af.ok() {
- ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
- return false
- }
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- default:
- ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
- }
- case androidAppTag:
- if ap, ok := child.(*java.AndroidApp); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
- return true // track transitive dependencies
- } else if ap, ok := child.(*java.AndroidAppImport); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
- } else if ap, ok := child.(*java.AndroidTestHelperApp); ok {
- filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
- } else if ap, ok := child.(*java.AndroidAppSet); ok {
- appDir := "app"
- if ap.Privileged() {
- appDir = "priv-app"
- }
- // TODO(b/224589412, b/226559955): Ensure that the dirname is
- // suffixed so that PackageManager correctly invalidates the
- // existing installed apk in favour of the new APK-in-APEX.
- // See bugs for more information.
- appDirName := filepath.Join(appDir, ap.BaseModuleName()+"@"+sanitizedBuildIdForPath(ctx))
- af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
- af.certificate = java.PresignedCertificate
- filesInfo = append(filesInfo, af)
- } else {
- ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
- }
- case rroTag:
- if rro, ok := child.(java.RuntimeResourceOverlayModule); ok {
- filesInfo = append(filesInfo, apexFileForRuntimeResourceOverlay(ctx, rro))
- } else {
- ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName)
- }
- case bpfTag:
- if bpfProgram, ok := child.(bpf.BpfModule); ok {
- filesToCopy, _ := bpfProgram.OutputFiles("")
- apex_sub_dir := bpfProgram.SubDir()
- for _, bpfFile := range filesToCopy {
- filesInfo = append(filesInfo, apexFileForBpfProgram(ctx, bpfFile, apex_sub_dir, bpfProgram))
- }
- } else {
- ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName)
- }
- case fsTag:
- if fs, ok := child.(filesystem.Filesystem); ok {
- filesInfo = append(filesInfo, apexFileForFilesystem(ctx, fs.OutputPath(), fs))
- } else {
- ctx.PropertyErrorf("filesystems", "%q is not a filesystem module", depName)
- }
- case prebuiltTag:
- if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
- filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
- } else {
- ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
- }
- case compatConfigTag:
- if compatConfig, ok := child.(java.PlatformCompatConfigIntf); ok {
- filesInfo = append(filesInfo, apexFileForCompatConfig(ctx, compatConfig, depName))
- } else {
- ctx.PropertyErrorf("compat_configs", "%q is not a platform_compat_config module", depName)
- }
- case testTag:
- if ccTest, ok := child.(*cc.Module); ok {
- if ccTest.IsTestPerSrcAllTestsVariation() {
- // Multiple-output test module (where `test_per_src: true`).
- //
- // `ccTest` is the "" ("all tests") variation of a `test_per_src` module.
- // We do not add this variation to `filesInfo`, as it has no output;
- // however, we do add the other variations of this module as indirect
- // dependencies (see below).
- } else {
- // Single-output test module (where `test_per_src: false`).
- af := apexFileForExecutable(ctx, ccTest)
- af.class = nativeTest
- filesInfo = append(filesInfo, af)
- }
- return true // track transitive dependencies
- } else {
- ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
- }
- case keyTag:
- if key, ok := child.(*apexKey); ok {
- a.privateKeyFile = key.privateKeyFile
- a.publicKeyFile = key.publicKeyFile
- } else {
- ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
- }
- return false
- case certificateTag:
- if dep, ok := child.(*java.AndroidAppCertificate); ok {
- a.containerCertificateFile = dep.Certificate.Pem
- a.containerPrivateKeyFile = dep.Certificate.Key
- } else {
- ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
- }
- case android.PrebuiltDepTag:
- // If the prebuilt is force disabled, remember to delete the prebuilt file
- // that might have been installed in the previous builds
- if prebuilt, ok := child.(prebuilt); ok && prebuilt.isForceDisabled() {
- a.prebuiltFileToDelete = prebuilt.InstallFilename()
- }
- }
- } else if !a.vndkApex {
- // indirect dependencies
- if am, ok := child.(android.ApexModule); ok {
- // We cannot use a switch statement on `depTag` here as the checked
- // tags used below are private (e.g. `cc.sharedDepTag`).
- if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
- if cc, ok := child.(*cc.Module); ok {
- if cc.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && cc.IsVndk() {
- requireNativeLibs = append(requireNativeLibs, ":vndk")
- return false
- }
- af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
- af.transitiveDep = true
-
- // Always track transitive dependencies for host.
- if a.Host() {
- filesInfo = append(filesInfo, af)
- return true
- }
-
- abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
- if !abInfo.Contents.DirectlyInApex(depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
- // If the dependency is a stubs lib, don't include it in this APEX,
- // but make sure that the lib is installed on the device.
- // In case no APEX is having the lib, the lib is installed to the system
- // partition.
- //
- // Always include if we are a host-apex however since those won't have any
- // system libraries.
- if !am.DirectlyInAnyApex() {
- // we need a module name for Make
- name := cc.ImplementationModuleNameForMake(ctx) + cc.Properties.SubName
- if !android.InList(name, a.requiredDeps) {
- a.requiredDeps = append(a.requiredDeps, name)
- }
- }
- requireNativeLibs = append(requireNativeLibs, af.stem())
- // Don't track further
- return false
- }
-
- // If the dep is not considered to be in the same
- // apex, don't add it to filesInfo so that it is not
- // included in this APEX.
- // TODO(jiyong): move this to at the top of the
- // else-if clause for the indirect dependencies.
- // Currently, that's impossible because we would
- // like to record requiredNativeLibs even when
- // DepIsInSameAPex is false. We also shouldn't do
- // this for host.
- //
- // TODO(jiyong): explain why the same module is passed in twice.
- // Switching the first am to parent breaks lots of tests.
- if !android.IsDepInSameApex(ctx, am, am) {
- return false
- }
-
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- } else if rm, ok := child.(*rust.Module); ok {
- af := apexFileForRustLibrary(ctx, rm)
- af.transitiveDep = true
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- }
- } else if cc.IsTestPerSrcDepTag(depTag) {
- if cc, ok := child.(*cc.Module); ok {
- af := apexFileForExecutable(ctx, cc)
- // Handle modules created as `test_per_src` variations of a single test module:
- // use the name of the generated test binary (`fileToCopy`) instead of the name
- // of the original test module (`depName`, shared by all `test_per_src`
- // variations of that module).
- af.androidMkModuleName = filepath.Base(af.builtFile.String())
- // these are not considered transitive dep
- af.transitiveDep = false
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- }
- } else if cc.IsHeaderDepTag(depTag) {
- // nothing
- } else if java.IsJniDepTag(depTag) {
- // Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
- return false
- } else if java.IsXmlPermissionsFileDepTag(depTag) {
- if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
- filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
- }
- } else if rust.IsDylibDepTag(depTag) {
- if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
- af := apexFileForRustLibrary(ctx, rustm)
- af.transitiveDep = true
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- }
- } else if rust.IsRlibDepTag(depTag) {
- // Rlib is statically linked, but it might have shared lib
- // dependencies. Track them.
- return true
- } else if java.IsBootclasspathFragmentContentDepTag(depTag) {
- // Add the contents of the bootclasspath fragment to the apex.
- switch child.(type) {
- case *java.Library, *java.SdkLibrary:
- javaModule := child.(javaModule)
- af := apexFileForBootclasspathFragmentContentModule(ctx, parent, javaModule)
- if !af.ok() {
- ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q is not configured to be compiled into dex", depName)
- return false
- }
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- default:
- ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
- }
- } else if java.IsSystemServerClasspathFragmentContentDepTag(depTag) {
- // Add the contents of the systemserverclasspath fragment to the apex.
- switch child.(type) {
- case *java.Library, *java.SdkLibrary:
- af := apexFileForJavaModule(ctx, child.(javaModule))
- filesInfo = append(filesInfo, af)
- return true // track transitive dependencies
- default:
- ctx.PropertyErrorf("systemserverclasspath_fragments", "systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
- }
- } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
- // nothing
- } else if depTag == android.DarwinUniversalVariantTag {
- // nothing
- } else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
- ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
- }
- }
- }
- return false
- })
- if a.privateKeyFile == nil {
- ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.overridableProperties.Key))
+ bazelCtx := ctx.Config().BazelContext
+ outputs, err := bazelCtx.GetApexInfo(a.GetBazelLabel(ctx, a), android.GetConfigKey(ctx))
+ if err != nil {
+ ctx.ModuleErrorf(err.Error())
return
}
-
- // Remove duplicates in filesInfo
- removeDup := func(filesInfo []apexFile) []apexFile {
- encountered := make(map[string]apexFile)
- for _, f := range filesInfo {
- dest := filepath.Join(f.installDir, f.builtFile.Base())
- if e, ok := encountered[dest]; !ok {
- encountered[dest] = f
- } else {
- // If a module is directly included and also transitively depended on
- // consider it as directly included.
- e.transitiveDep = e.transitiveDep && f.transitiveDep
- encountered[dest] = e
- }
- }
- var result []apexFile
- for _, v := range encountered {
- result = append(result, v)
- }
- return result
- }
- filesInfo = removeDup(filesInfo)
-
- // Sort to have consistent build rules
- sort.Slice(filesInfo, func(i, j int) bool {
- // Sort by destination path so as to ensure consistent ordering even if the source of the files
- // changes.
- return filesInfo[i].path() < filesInfo[j].path()
- })
-
- ////////////////////////////////////////////////////////////////////////////////////////////
- // 3) some fields in apexBundle struct are configured
a.installDir = android.PathForModuleInstall(ctx, "apex")
- a.filesInfo = filesInfo
+ a.outputApexFile = android.PathForBazelOut(ctx, outputs.SignedOutput)
+ a.outputFile = a.outputApexFile
+ a.setCompression(ctx)
+ a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[0])
+ a.privateKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[1])
+ a.containerCertificateFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[0])
+ a.containerPrivateKeyFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[1])
+ apexType := a.properties.ApexType
+ switch apexType {
+ case imageApex:
+ // TODO(asmundak): Bazel does not create these files yet.
+ // b/190817312
+ a.htmlGzNotice = android.PathForBazelOut(ctx, "NOTICE.html.gz")
+ // b/239081457
+ a.bundleModuleFile = android.PathForBazelOut(ctx, a.Name()+apexType.suffix()+"-base.zip")
+ // b/239081455
+ a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.txt"))
+ // b/239081456
+ a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_backing.txt"))
+ // b/239084755
+ a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.xml"))
+ installSuffix := imageApexSuffix
+ if a.isCompressed {
+ installSuffix = imageCapexSuffix
+ }
+ a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
+ a.compatSymlinks.Paths()...)
+ default:
+ panic(fmt.Errorf("unexpected apex_type for the ProcessBazelQuery: %v", a.properties.ApexType))
+ }
+
+ /*
+ TODO(asmundak): compared to building an APEX with Soong, building it with Bazel does not
+ return filesInfo and requiredDeps fields (in the Soong build the latter is updated).
+ Fix this, as these fields are subsequently used in apex/androidmk.go and in apex/builder/go
+ To find out what Soong build puts there, run:
+ vctx := visitorContext{handleSpecialLibs: !android.Bool(a.properties.Ignore_system_library_special_case)}
+ ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
+ return a.depVisitor(&vctx, ctx, child, parent)
+ })
+ vctx.normalizeFileInfo()
+ */
+
+}
+
+func (a *apexBundle) setCompression(ctx android.ModuleContext) {
+ if a.properties.ApexType != imageApex {
+ a.isCompressed = false
+ } else if a.testOnlyShouldForceCompression() {
+ a.isCompressed = true
+ } else {
+ a.isCompressed = ctx.Config().ApexCompressionEnabled() && a.isCompressable()
+ }
+}
+
+func (a *apexBundle) setSystemLibLink(ctx android.ModuleContext) {
+ // Optimization. If we are building bundled APEX, for the files that are gathered due to the
+ // transitive dependencies, don't place them inside the APEX, but place a symlink pointing
+ // the same library in the system partition, thus effectively sharing the same libraries
+ // across the APEX boundary. For unbundled APEX, all the gathered files are actually placed
+ // in the APEX.
+ a.linkToSystemLib = !ctx.Config().UnbundledBuild() && a.installable()
+
+ // APEXes targeting other than system/system_ext partitions use vendor/product variants.
+ // So we can't link them to /system/lib libs which are core variants.
+ if a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+ a.linkToSystemLib = false
+ }
+
+ forced := ctx.Config().ForceApexSymlinkOptimization()
+ updatable := a.Updatable() || a.FutureUpdatable()
+
+ // We don't need the optimization for updatable APEXes, as it might give false signal
+ // to the system health when the APEXes are still bundled (b/149805758).
+ if !forced && updatable && a.properties.ApexType == imageApex {
+ a.linkToSystemLib = false
+ }
+
+ // We also don't want the optimization for host APEXes, because it doesn't make sense.
+ if ctx.Host() {
+ a.linkToSystemLib = false
+ }
+}
+
+func (a *apexBundle) setPayloadFsType(ctx android.ModuleContext) {
+ switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) {
+ case ext4FsType:
+ a.payloadFsType = ext4
+ case f2fsFsType:
+ a.payloadFsType = f2fs
+ case erofsFsType:
+ a.payloadFsType = erofs
+ default:
+ ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs, erofs]", *a.properties.Payload_fs_type)
+ }
+}
+
+func (a *apexBundle) setApexTypeAndSuffix(ctx android.ModuleContext) {
// Set suffix and primaryApexType depending on the ApexType
buildFlattenedAsDefault := ctx.Config().FlattenApex()
switch a.properties.ApexType {
@@ -2222,52 +1963,444 @@
a.suffix = flattenedSuffix
}
}
+}
- switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) {
- case ext4FsType:
- a.payloadFsType = ext4
- case f2fsFsType:
- a.payloadFsType = f2fs
- case erofsFsType:
- a.payloadFsType = erofs
- default:
- ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs, erofs]", *a.properties.Payload_fs_type)
+func (a apexBundle) isCompressable() bool {
+ return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex
+}
+
+func (a *apexBundle) commonBuildActions(ctx android.ModuleContext) bool {
+ a.checkApexAvailability(ctx)
+ a.checkUpdatable(ctx)
+ a.CheckMinSdkVersion(ctx)
+ a.checkStaticLinkingToStubLibraries(ctx)
+ a.checkStaticExecutables(ctx)
+ if len(a.properties.Tests) > 0 && !a.testApex {
+ ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
+ return false
+ }
+ return true
+}
+
+type visitorContext struct {
+ // all the files that will be included in this APEX
+ filesInfo []apexFile
+
+ // native lib dependencies
+ provideNativeLibs []string
+ requireNativeLibs []string
+
+ handleSpecialLibs bool
+}
+
+func (vctx *visitorContext) normalizeFileInfo() {
+ encountered := make(map[string]apexFile)
+ for _, f := range vctx.filesInfo {
+ dest := filepath.Join(f.installDir, f.builtFile.Base())
+ if e, ok := encountered[dest]; !ok {
+ encountered[dest] = f
+ } else {
+ // If a module is directly included and also transitively depended on
+ // consider it as directly included.
+ e.transitiveDep = e.transitiveDep && f.transitiveDep
+ encountered[dest] = e
+ }
+ }
+ vctx.filesInfo = vctx.filesInfo[:0]
+ for _, v := range encountered {
+ vctx.filesInfo = append(vctx.filesInfo, v)
+ }
+ sort.Slice(vctx.filesInfo, func(i, j int) bool {
+ // Sort by destination path so as to ensure consistent ordering even if the source of the files
+ // changes.
+ return vctx.filesInfo[i].path() < vctx.filesInfo[j].path()
+ })
+}
+
+func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, child, parent blueprint.Module) bool {
+ depTag := ctx.OtherModuleDependencyTag(child)
+ if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
+ return false
+ }
+ if mod, ok := child.(android.Module); ok && !mod.Enabled() {
+ return false
+ }
+ depName := ctx.OtherModuleName(child)
+ if _, isDirectDep := parent.(*apexBundle); isDirectDep {
+ switch depTag {
+ case sharedLibTag, jniLibTag:
+ isJniLib := depTag == jniLibTag
+ switch ch := child.(type) {
+ case *cc.Module:
+ fi := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
+ fi.isJniLib = isJniLib
+ vctx.filesInfo = append(vctx.filesInfo, fi)
+ // Collect the list of stub-providing libs except:
+ // - VNDK libs are only for vendors
+ // - bootstrap bionic libs are treated as provided by system
+ if ch.HasStubsVariants() && !a.vndkApex && !cc.InstallToBootstrap(ch.BaseModuleName(), ctx.Config()) {
+ vctx.provideNativeLibs = append(vctx.provideNativeLibs, fi.stem())
+ }
+ return true // track transitive dependencies
+ case *rust.Module:
+ fi := apexFileForRustLibrary(ctx, ch)
+ fi.isJniLib = isJniLib
+ vctx.filesInfo = append(vctx.filesInfo, fi)
+ return true // track transitive dependencies
+ default:
+ propertyName := "native_shared_libs"
+ if isJniLib {
+ propertyName = "jni_libs"
+ }
+ ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
+ }
+ case executableTag:
+ switch ch := child.(type) {
+ case *cc.Module:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, ch))
+ return true // track transitive dependencies
+ case *python.Module:
+ if ch.HostToolPath().Valid() {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForPyBinary(ctx, ch))
+ }
+ case bootstrap.GoBinaryTool:
+ if a.Host() {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForGoBinary(ctx, depName, ch))
+ }
+ case *rust.Module:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, ch))
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("binaries",
+ "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, nor (host) bootstrap_go_binary", depName)
+ }
+ case shBinaryTag:
+ if csh, ok := child.(*sh.ShBinary); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForShBinary(ctx, csh))
+ } else {
+ ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName)
+ }
+ case bcpfTag:
+ bcpfModule, ok := child.(*java.BootclasspathFragmentModule)
+ if !ok {
+ ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a bootclasspath_fragment module", depName)
+ return false
+ }
+
+ vctx.filesInfo = append(vctx.filesInfo, apexBootclasspathFragmentFiles(ctx, child)...)
+ for _, makeModuleName := range bcpfModule.BootImageDeviceInstallMakeModules() {
+ a.requiredDeps = append(a.requiredDeps, makeModuleName)
+ }
+ return true
+ case sscpfTag:
+ if _, ok := child.(*java.SystemServerClasspathModule); !ok {
+ ctx.PropertyErrorf("systemserverclasspath_fragments",
+ "%q is not a systemserverclasspath_fragment module", depName)
+ return false
+ }
+ if af := apexClasspathFragmentProtoFile(ctx, child); af != nil {
+ vctx.filesInfo = append(vctx.filesInfo, *af)
+ }
+ return true
+ case javaLibTag:
+ switch child.(type) {
+ case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import:
+ af := apexFileForJavaModule(ctx, child.(javaModule))
+ if !af.ok() {
+ ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
+ return false
+ }
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ }
+ case androidAppTag:
+ switch ap := child.(type) {
+ case *java.AndroidApp:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ return true // track transitive dependencies
+ case *java.AndroidAppImport:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ case *java.AndroidTestHelperApp:
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ case *java.AndroidAppSet:
+ appDir := "app"
+ if ap.Privileged() {
+ appDir = "priv-app"
+ }
+ // TODO(b/224589412, b/226559955): Ensure that the dirname is
+ // suffixed so that PackageManager correctly invalidates the
+ // existing installed apk in favour of the new APK-in-APEX.
+ // See bugs for more information.
+ appDirName := filepath.Join(appDir, ap.BaseModuleName()+"@"+sanitizedBuildIdForPath(ctx))
+ af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
+ af.certificate = java.PresignedCertificate
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ default:
+ ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
+ }
+ case rroTag:
+ if rro, ok := child.(java.RuntimeResourceOverlayModule); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForRuntimeResourceOverlay(ctx, rro))
+ } else {
+ ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName)
+ }
+ case bpfTag:
+ if bpfProgram, ok := child.(bpf.BpfModule); ok {
+ filesToCopy, _ := bpfProgram.OutputFiles("")
+ apex_sub_dir := bpfProgram.SubDir()
+ for _, bpfFile := range filesToCopy {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForBpfProgram(ctx, bpfFile, apex_sub_dir, bpfProgram))
+ }
+ } else {
+ ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName)
+ }
+ case fsTag:
+ if fs, ok := child.(filesystem.Filesystem); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForFilesystem(ctx, fs.OutputPath(), fs))
+ } else {
+ ctx.PropertyErrorf("filesystems", "%q is not a filesystem module", depName)
+ }
+ case prebuiltTag:
+ if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+ } else {
+ ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
+ }
+ case compatConfigTag:
+ if compatConfig, ok := child.(java.PlatformCompatConfigIntf); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForCompatConfig(ctx, compatConfig, depName))
+ } else {
+ ctx.PropertyErrorf("compat_configs", "%q is not a platform_compat_config module", depName)
+ }
+ case testTag:
+ if ccTest, ok := child.(*cc.Module); ok {
+ if ccTest.IsTestPerSrcAllTestsVariation() {
+ // Multiple-output test module (where `test_per_src: true`).
+ //
+ // `ccTest` is the "" ("all tests") variation of a `test_per_src` module.
+ // We do not add this variation to `filesInfo`, as it has no output;
+ // however, we do add the other variations of this module as indirect
+ // dependencies (see below).
+ } else {
+ // Single-output test module (where `test_per_src: false`).
+ af := apexFileForExecutable(ctx, ccTest)
+ af.class = nativeTest
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ }
+ return true // track transitive dependencies
+ } else {
+ ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
+ }
+ case keyTag:
+ if key, ok := child.(*apexKey); ok {
+ a.privateKeyFile = key.privateKeyFile
+ a.publicKeyFile = key.publicKeyFile
+ } else {
+ ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
+ }
+ case certificateTag:
+ if dep, ok := child.(*java.AndroidAppCertificate); ok {
+ a.containerCertificateFile = dep.Certificate.Pem
+ a.containerPrivateKeyFile = dep.Certificate.Key
+ } else {
+ ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
+ }
+ case android.PrebuiltDepTag:
+ // If the prebuilt is force disabled, remember to delete the prebuilt file
+ // that might have been installed in the previous builds
+ if prebuilt, ok := child.(prebuilt); ok && prebuilt.isForceDisabled() {
+ a.prebuiltFileToDelete = prebuilt.InstallFilename()
+ }
+ }
+ return false
}
- // Optimization. If we are building bundled APEX, for the files that are gathered due to the
- // transitive dependencies, don't place them inside the APEX, but place a symlink pointing
- // the same library in the system partition, thus effectively sharing the same libraries
- // across the APEX boundary. For unbundled APEX, all the gathered files are actually placed
- // in the APEX.
- a.linkToSystemLib = !ctx.Config().UnbundledBuild() && a.installable()
-
- // APEXes targeting other than system/system_ext partitions use vendor/product variants.
- // So we can't link them to /system/lib libs which are core variants.
- if a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
- a.linkToSystemLib = false
+ if a.vndkApex {
+ return false
}
- forced := ctx.Config().ForceApexSymlinkOptimization()
- updatable := a.Updatable() || a.FutureUpdatable()
+ // indirect dependencies
+ am, ok := child.(android.ApexModule)
+ if !ok {
+ return false
+ }
+ // We cannot use a switch statement on `depTag` here as the checked
+ // tags used below are private (e.g. `cc.sharedDepTag`).
+ if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
+ if ch, ok := child.(*cc.Module); ok {
+ if ch.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && ch.IsVndk() {
+ vctx.requireNativeLibs = append(vctx.requireNativeLibs, ":vndk")
+ return false
+ }
+ af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
+ af.transitiveDep = true
- // We don't need the optimization for updatable APEXes, as it might give false signal
- // to the system health when the APEXes are still bundled (b/149805758).
- if !forced && updatable && a.properties.ApexType == imageApex {
- a.linkToSystemLib = false
+ // Always track transitive dependencies for host.
+ if a.Host() {
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true
+ }
+
+ abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
+ if !abInfo.Contents.DirectlyInApex(depName) && (ch.IsStubs() || ch.HasStubsVariants()) {
+ // If the dependency is a stubs lib, don't include it in this APEX,
+ // but make sure that the lib is installed on the device.
+ // In case no APEX is having the lib, the lib is installed to the system
+ // partition.
+ //
+ // Always include if we are a host-apex however since those won't have any
+ // system libraries.
+ if !am.DirectlyInAnyApex() {
+ // we need a module name for Make
+ name := ch.ImplementationModuleNameForMake(ctx) + ch.Properties.SubName
+ if !android.InList(name, a.requiredDeps) {
+ a.requiredDeps = append(a.requiredDeps, name)
+ }
+ }
+ vctx.requireNativeLibs = append(vctx.requireNativeLibs, af.stem())
+ // Don't track further
+ return false
+ }
+
+ // If the dep is not considered to be in the same
+ // apex, don't add it to filesInfo so that it is not
+ // included in this APEX.
+ // TODO(jiyong): move this to at the top of the
+ // else-if clause for the indirect dependencies.
+ // Currently, that's impossible because we would
+ // like to record requiredNativeLibs even when
+ // DepIsInSameAPex is false. We also shouldn't do
+ // this for host.
+ //
+ // TODO(jiyong): explain why the same module is passed in twice.
+ // Switching the first am to parent breaks lots of tests.
+ if !android.IsDepInSameApex(ctx, am, am) {
+ return false
+ }
+
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ } else if rm, ok := child.(*rust.Module); ok {
+ af := apexFileForRustLibrary(ctx, rm)
+ af.transitiveDep = true
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ }
+ } else if cc.IsTestPerSrcDepTag(depTag) {
+ if ch, ok := child.(*cc.Module); ok {
+ af := apexFileForExecutable(ctx, ch)
+ // Handle modules created as `test_per_src` variations of a single test module:
+ // use the name of the generated test binary (`fileToCopy`) instead of the name
+ // of the original test module (`depName`, shared by all `test_per_src`
+ // variations of that module).
+ af.androidMkModuleName = filepath.Base(af.builtFile.String())
+ // these are not considered transitive dep
+ af.transitiveDep = false
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ }
+ } else if cc.IsHeaderDepTag(depTag) {
+ // nothing
+ } else if java.IsJniDepTag(depTag) {
+ // Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
+ } else if java.IsXmlPermissionsFileDepTag(depTag) {
+ if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
+ vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+ }
+ } else if rust.IsDylibDepTag(depTag) {
+ if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
+ af := apexFileForRustLibrary(ctx, rustm)
+ af.transitiveDep = true
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ }
+ } else if rust.IsRlibDepTag(depTag) {
+ // Rlib is statically linked, but it might have shared lib
+ // dependencies. Track them.
+ return true
+ } else if java.IsBootclasspathFragmentContentDepTag(depTag) {
+ // Add the contents of the bootclasspath fragment to the apex.
+ switch child.(type) {
+ case *java.Library, *java.SdkLibrary:
+ javaModule := child.(javaModule)
+ af := apexFileForBootclasspathFragmentContentModule(ctx, parent, javaModule)
+ if !af.ok() {
+ ctx.PropertyErrorf("bootclasspath_fragments",
+ "bootclasspath_fragment content %q is not configured to be compiled into dex", depName)
+ return false
+ }
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("bootclasspath_fragments",
+ "bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ }
+ } else if java.IsSystemServerClasspathFragmentContentDepTag(depTag) {
+ // Add the contents of the systemserverclasspath fragment to the apex.
+ switch child.(type) {
+ case *java.Library, *java.SdkLibrary:
+ af := apexFileForJavaModule(ctx, child.(javaModule))
+ vctx.filesInfo = append(vctx.filesInfo, af)
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("systemserverclasspath_fragments",
+ "systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ }
+ } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
+ // nothing
+ } else if depTag == android.DarwinUniversalVariantTag {
+ // nothing
+ } else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
+ ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
+ }
+ return false
+}
+
+// Creates build rules for an APEX. It consists of the following major steps:
+//
+// 1) do some validity checks such as apex_available, min_sdk_version, etc.
+// 2) traverse the dependency tree to collect apexFile structs from them.
+// 3) some fields in apexBundle struct are configured
+// 4) generate the build rules to create the APEX. This is mostly done in builder.go.
+func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // 1) do some validity checks such as apex_available, min_sdk_version, etc.
+ if !a.commonBuildActions(ctx) {
+ return
+ }
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // 2) traverse the dependency tree to collect apexFile structs from them.
+
+ // Collect the module directory for IDE info in java/jdeps.go.
+ a.modulePaths = append(a.modulePaths, ctx.ModuleDir())
+
+ // TODO(jiyong): do this using WalkPayloadDeps
+ // TODO(jiyong): make this clean!!!
+ vctx := visitorContext{handleSpecialLibs: !android.Bool(a.properties.Ignore_system_library_special_case)}
+ ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) })
+ vctx.normalizeFileInfo()
+ if a.privateKeyFile == nil {
+ ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.overridableProperties.Key))
+ return
}
- // We also don't want the optimization for host APEXes, because it doesn't make sense.
- if ctx.Host() {
- a.linkToSystemLib = false
- }
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // 3) some fields in apexBundle struct are configured
+ a.installDir = android.PathForModuleInstall(ctx, "apex")
+ a.filesInfo = vctx.filesInfo
+ a.setApexTypeAndSuffix(ctx)
+ a.setPayloadFsType(ctx)
+ a.setSystemLibLink(ctx)
if a.properties.ApexType != zipApex {
a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
}
////////////////////////////////////////////////////////////////////////////////////////////
// 4) generate the build rules to create the APEX. This is done in builder.go.
- a.buildManifest(ctx, provideNativeLibs, requireNativeLibs)
+ a.buildManifest(ctx, vctx.provideNativeLibs, vctx.requireNativeLibs)
if a.properties.ApexType == flattenedApex {
a.buildFlattenedApex(ctx)
} else {
@@ -2458,7 +2591,7 @@
android.BazelModuleBase
}
-func (o *OverrideApex) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (o *OverrideApex) GenerateAndroidBuildActions(_ android.ModuleContext) {
// All the overrides happen in the base module.
}
@@ -2523,13 +2656,36 @@
}
// Prebuilts
- prebuiltsLabelList := android.BazelLabelForModuleDeps(ctx, overridableProperties.Prebuilts)
- attrs.Prebuilts = bazel.MakeLabelListAttribute(prebuiltsLabelList)
+ if overridableProperties.Prebuilts != nil {
+ prebuiltsLabelList := android.BazelLabelForModuleDeps(ctx, overridableProperties.Prebuilts)
+ attrs.Prebuilts = bazel.MakeLabelListAttribute(prebuiltsLabelList)
+ }
// Compressible
if overridableProperties.Compressible != nil {
attrs.Compressible = bazel.BoolAttribute{Value: overridableProperties.Compressible}
}
+
+ // Package name
+ //
+ // e.g. com.android.adbd's package name is com.android.adbd, but
+ // com.google.android.adbd overrides the package name to com.google.android.adbd
+ //
+ // TODO: this can be overridden from the product configuration, see
+ // getOverrideManifestPackageName and
+ // PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES.
+ //
+ // Instead of generating the BUILD files differently based on the product config
+ // at the point of conversion, this should be handled by the BUILD file loading
+ // from the soong_injection's product_vars, so product config is decoupled from bp2build.
+ if overridableProperties.Package_name != "" {
+ attrs.Package_name = &overridableProperties.Package_name
+ }
+
+ // Logging parent
+ if overridableProperties.Logging_parent != "" {
+ attrs.Logging_parent = &overridableProperties.Logging_parent
+ }
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: o.Name()}, &attrs)
@@ -2545,7 +2701,7 @@
var _ android.ModuleWithMinSdkVersionCheck = (*apexBundle)(nil)
-// Entures that min_sdk_version of the included modules are equal or less than the min_sdk_version
+// Ensures that min_sdk_version of the included modules are equal or less than the min_sdk_version
// of this apexBundle.
func (a *apexBundle) CheckMinSdkVersion(ctx android.ModuleContext) {
if a.testApex || a.vndkApex {
@@ -2859,34 +3015,9 @@
//
// Module separator
//
- m["com.android.bluetooth"] = []string{
- "android.hardware.audio.common@5.0",
- "android.hardware.bluetooth.a2dp@1.0",
- "android.hardware.bluetooth.audio@2.0",
- "android.hardware.bluetooth@1.0",
- "android.hardware.bluetooth@1.1",
- "android.hardware.graphics.bufferqueue@1.0",
- "android.hardware.graphics.bufferqueue@2.0",
- "android.hardware.graphics.common@1.0",
- "android.hardware.graphics.common@1.1",
- "android.hardware.graphics.common@1.2",
- "android.hardware.media@1.0",
- "android.hidl.safe_union@1.0",
- "android.hidl.token@1.0",
- "android.hidl.token@1.0-utils",
- "avrcp-target-service",
- "avrcp_headers",
+ m["com.android.btservices"] = []string{
"bluetooth-protos-lite",
- "bluetooth.mapsapi",
- "com.android.vcard",
- "dnsresolver_aidl_interface-V2-java",
- "ipmemorystore-aidl-interfaces-V5-java",
- "ipmemorystore-aidl-interfaces-java",
"internal_include_headers",
- "lib-bt-packets",
- "lib-bt-packets-avrcp",
- "lib-bt-packets-base",
- "libFraunhoferAAC",
"libaudio-a2dp-hw-utils",
"libaudio-hearing-aid-hw-utils",
"libbluetooth",
@@ -2910,28 +3041,36 @@
"libbte",
"libbtif",
"libchrome",
- "libevent",
- "libfmq",
- "libg722codec",
- "libgui_headers",
- "libmedia_headers",
- "libmodpb64",
- "libosi",
- "libstagefright_foundation_headers",
- "libstagefright_headers",
- "libstatslog",
- "libstatssocket",
- "libtinyxml2",
- "libudrv-uipc",
- "libz",
- "media_plugin_headers",
- "net-utils-services-common",
- "netd_aidl_interface-unstable-java",
- "netd_event_listener_interface-java",
- "netlink-client",
- "networkstack-client",
- "sap-api-java-static",
- "services.net",
+ }
+ //
+ // Module separator
+ //
+ m["com.android.bluetooth"] = []string{
+ "bluetooth-protos-lite",
+ "internal_include_headers",
+ "libaudio-a2dp-hw-utils",
+ "libaudio-hearing-aid-hw-utils",
+ "libbluetooth",
+ "libbluetooth-types",
+ "libbluetooth-types-header",
+ "libbluetooth_gd",
+ "libbluetooth_headers",
+ "libbluetooth_jni",
+ "libbt-audio-hal-interface",
+ "libbt-bta",
+ "libbt-common",
+ "libbt-hci",
+ "libbt-platform-protos-lite",
+ "libbt-protos-lite",
+ "libbt-sbc-decoder",
+ "libbt-sbc-encoder",
+ "libbt-stack",
+ "libbt-utils",
+ "libbtcore",
+ "libbtdevice",
+ "libbte",
+ "libbtif",
+ "libchrome",
}
//
// Module separator
@@ -2971,258 +3110,13 @@
// Module separator
//
m["com.android.media"] = []string{
- "android.frameworks.bufferhub@1.0",
- "android.hardware.cas.native@1.0",
- "android.hardware.cas@1.0",
- "android.hardware.configstore-utils",
- "android.hardware.configstore@1.0",
- "android.hardware.configstore@1.1",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
- "android.hardware.graphics.bufferqueue@1.0",
- "android.hardware.graphics.bufferqueue@2.0",
- "android.hardware.graphics.common@1.0",
- "android.hardware.graphics.common@1.1",
- "android.hardware.graphics.common@1.2",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@2.1",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.media.omx@1.0",
- "android.hardware.media@1.0",
- "android.hidl.allocator@1.0",
- "android.hidl.memory.token@1.0",
- "android.hidl.memory@1.0",
- "android.hidl.token@1.0",
- "android.hidl.token@1.0-utils",
- "bionic_libc_platform_headers",
- "exoplayer2-extractor",
- "exoplayer2-extractor-annotation-stubs",
- "gl_headers",
- "jsr305",
- "libEGL",
- "libEGL_blobCache",
- "libEGL_getProcAddress",
- "libFLAC",
- "libFLAC-config",
- "libFLAC-headers",
- "libGLESv2",
- "libaacextractor",
- "libamrextractor",
- "libarect",
- "libaudio_system_headers",
- "libaudioclient",
- "libaudioclient_headers",
- "libaudiofoundation",
- "libaudiofoundation_headers",
- "libaudiomanager",
- "libaudiopolicy",
- "libaudioutils",
- "libaudioutils_fixedfft",
- "libbluetooth-types-header",
- "libbufferhub",
- "libbufferhub_headers",
- "libbufferhubqueue",
- "libc_malloc_debug_backtrace",
- "libcamera_client",
- "libcamera_metadata",
- "libdvr_headers",
- "libexpat",
- "libfifo",
- "libflacextractor",
- "libgrallocusage",
- "libgraphicsenv",
- "libgui",
- "libgui_headers",
- "libhardware_headers",
- "libinput",
- "liblzma",
- "libmath",
- "libmedia",
- "libmedia_codeclist",
- "libmedia_headers",
- "libmedia_helper",
- "libmedia_helper_headers",
- "libmedia_midiiowrapper",
- "libmedia_omx",
- "libmediautils",
- "libmidiextractor",
- "libmkvextractor",
- "libmp3extractor",
- "libmp4extractor",
- "libmpeg2extractor",
- "libnativebase_headers",
- "libnativewindow_headers",
- "libnblog",
- "liboggextractor",
- "libpackagelistparser",
- "libpdx",
- "libpdx_default_transport",
- "libpdx_headers",
- "libpdx_uds",
- "libprocinfo",
- "libspeexresampler",
- "libspeexresampler",
- "libstagefright_esds",
- "libstagefright_flacdec",
- "libstagefright_flacdec",
- "libstagefright_foundation",
- "libstagefright_foundation_headers",
- "libstagefright_foundation_without_imemory",
- "libstagefright_headers",
- "libstagefright_id3",
- "libstagefright_metadatautils",
- "libstagefright_mpeg2extractor",
- "libstagefright_mpeg2support",
- "libui",
- "libui_headers",
- "libunwindstack",
- "libvibrator",
- "libvorbisidec",
- "libwavextractor",
- "libwebm",
- "media_ndk_headers",
- "media_plugin_headers",
- "updatable-media",
+ // empty
}
//
// Module separator
//
m["com.android.media.swcodec"] = []string{
- "android.frameworks.bufferhub@1.0",
- "android.hardware.common-ndk_platform",
- "android.hardware.configstore-utils",
- "android.hardware.configstore@1.0",
- "android.hardware.configstore@1.1",
- "android.hardware.graphics.allocator@2.0",
- "android.hardware.graphics.allocator@3.0",
- "android.hardware.graphics.allocator@4.0",
- "android.hardware.graphics.bufferqueue@1.0",
- "android.hardware.graphics.bufferqueue@2.0",
- "android.hardware.graphics.common-ndk_platform",
- "android.hardware.graphics.common@1.0",
- "android.hardware.graphics.common@1.1",
- "android.hardware.graphics.common@1.2",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@2.1",
- "android.hardware.graphics.mapper@3.0",
- "android.hardware.graphics.mapper@4.0",
- "android.hardware.media.bufferpool@2.0",
- "android.hardware.media.c2@1.0",
- "android.hardware.media.c2@1.1",
- "android.hardware.media.omx@1.0",
- "android.hardware.media@1.0",
- "android.hardware.media@1.0",
- "android.hidl.memory.token@1.0",
- "android.hidl.memory@1.0",
- "android.hidl.safe_union@1.0",
- "android.hidl.token@1.0",
- "android.hidl.token@1.0-utils",
- "libEGL",
- "libFLAC",
- "libFLAC-config",
- "libFLAC-headers",
- "libFraunhoferAAC",
- "libLibGuiProperties",
- "libarect",
- "libaudio_system_headers",
- "libaudioutils",
- "libaudioutils",
- "libaudioutils_fixedfft",
- "libavcdec",
- "libavcenc",
- "libavservices_minijail",
- "libavservices_minijail",
- "libbinderthreadstateutils",
- "libbluetooth-types-header",
- "libbufferhub_headers",
- "libcodec2",
- "libcodec2_headers",
- "libcodec2_hidl@1.0",
- "libcodec2_hidl@1.1",
- "libcodec2_internal",
- "libcodec2_soft_aacdec",
- "libcodec2_soft_aacenc",
- "libcodec2_soft_amrnbdec",
- "libcodec2_soft_amrnbenc",
- "libcodec2_soft_amrwbdec",
- "libcodec2_soft_amrwbenc",
- "libcodec2_soft_av1dec_gav1",
- "libcodec2_soft_avcdec",
- "libcodec2_soft_avcenc",
- "libcodec2_soft_common",
- "libcodec2_soft_flacdec",
- "libcodec2_soft_flacenc",
- "libcodec2_soft_g711alawdec",
- "libcodec2_soft_g711mlawdec",
- "libcodec2_soft_gsmdec",
- "libcodec2_soft_h263dec",
- "libcodec2_soft_h263enc",
- "libcodec2_soft_hevcdec",
- "libcodec2_soft_hevcenc",
- "libcodec2_soft_mp3dec",
- "libcodec2_soft_mpeg2dec",
- "libcodec2_soft_mpeg4dec",
- "libcodec2_soft_mpeg4enc",
- "libcodec2_soft_opusdec",
- "libcodec2_soft_opusenc",
- "libcodec2_soft_rawdec",
- "libcodec2_soft_vorbisdec",
- "libcodec2_soft_vp8dec",
- "libcodec2_soft_vp8enc",
- "libcodec2_soft_vp9dec",
- "libcodec2_soft_vp9enc",
- "libcodec2_vndk",
- "libdvr_headers",
- "libfmq",
- "libfmq",
- "libgav1",
- "libgralloctypes",
- "libgrallocusage",
- "libgraphicsenv",
- "libgsm",
- "libgui_bufferqueue_static",
- "libgui_headers",
- "libhardware",
- "libhardware_headers",
- "libhevcdec",
- "libhevcenc",
- "libion",
- "libjpeg",
- "liblzma",
- "libmath",
- "libmedia_codecserviceregistrant",
- "libmedia_headers",
- "libmpeg2dec",
- "libnativebase_headers",
- "libnativewindow_headers",
- "libpdx_headers",
- "libscudo_wrapper",
- "libsfplugin_ccodec_utils",
- "libspeexresampler",
- "libstagefright_amrnb_common",
- "libstagefright_amrnbdec",
- "libstagefright_amrnbenc",
- "libstagefright_amrwbdec",
- "libstagefright_amrwbenc",
- "libstagefright_bufferpool@2.0.1",
- "libstagefright_enc_common",
- "libstagefright_flacdec",
- "libstagefright_foundation",
- "libstagefright_foundation_headers",
- "libstagefright_headers",
- "libstagefright_m4vh263dec",
- "libstagefright_m4vh263enc",
- "libstagefright_mp3dec",
- "libui",
- "libui_headers",
- "libunwindstack",
- "libvorbisidec",
- "libvpx",
- "libyuv",
- "libyuv_static",
- "media_ndk_headers",
- "media_plugin_headers",
- "mediaswcodec",
+ // empty
}
//
// Module separator
@@ -3471,6 +3365,8 @@
Native_shared_libs_32 bazel.LabelListAttribute
Native_shared_libs_64 bazel.LabelListAttribute
Compressible bazel.BoolAttribute
+ Package_name *string
+ Logging_parent *string
}
type convertedNativeSharedLibs struct {
@@ -3565,6 +3461,16 @@
compressibleAttribute.Value = a.overridableProperties.Compressible
}
+ var packageName *string
+ if a.overridableProperties.Package_name != "" {
+ packageName = &a.overridableProperties.Package_name
+ }
+
+ var loggingParent *string
+ if a.overridableProperties.Logging_parent != "" {
+ loggingParent = &a.overridableProperties.Logging_parent
+ }
+
attrs := bazelApexBundleAttributes{
Manifest: manifestLabelAttribute,
Android_manifest: androidManifestLabelAttribute,
@@ -3579,6 +3485,8 @@
Binaries: binariesLabelListAttribute,
Prebuilts: prebuiltsLabelListAttribute,
Compressible: compressibleAttribute,
+ Package_name: packageName,
+ Logging_parent: loggingParent,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/apex/apex_sdk_member.go b/apex/apex_sdk_member.go
new file mode 100644
index 0000000..284158f
--- /dev/null
+++ b/apex/apex_sdk_member.go
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apex
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+// This file contains support for using apex modules within an sdk.
+
+func init() {
+ // Register sdk member types.
+ android.RegisterSdkMemberType(&apexSdkMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "apexes",
+ SupportsSdk: true,
+
+ // The apexes property does not need to be included in the snapshot as adding an apex to an
+ // sdk does not produce any prebuilts of the apex.
+ PrebuiltsRequired: proptools.BoolPtr(false),
+ },
+ })
+}
+
+type apexSdkMemberType struct {
+ android.SdkMemberTypeBase
+}
+
+func (mt *apexSdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (mt *apexSdkMemberType) IsInstance(module android.Module) bool {
+ _, ok := module.(*apexBundle)
+ return ok
+}
+
+func (mt *apexSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ panic("Sdk does not create prebuilts of the apexes in its snapshot")
+}
+
+func (mt *apexSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ panic("Sdk does not create prebuilts of the apexes in its snapshot")
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 07372a3..49a5d2a 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -26,6 +26,7 @@
"strings"
"testing"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -443,7 +444,6 @@
srcs: ["mylib.cpp"],
system_shared_libs: [],
stl: "none",
- notice: "custom_notice",
static_libs: ["libstatic"],
// TODO: remove //apex_available:platform
apex_available: [
@@ -467,7 +467,6 @@
srcs: ["mylib.cpp"],
system_shared_libs: [],
stl: "none",
- notice: "custom_notice_for_static_lib",
// TODO: remove //apex_available:platform
apex_available: [
"//apex_available:platform",
@@ -619,7 +618,7 @@
java_libs: ["myjar"],
apps: ["AppFoo"],
rros: ["rro"],
- bpfs: ["bpf", "netd_test"],
+ bpfs: ["bpf", "netdTest"],
updatable: false,
}
@@ -673,8 +672,8 @@
}
bpf {
- name: "netd_test",
- srcs: ["netd_test.c"],
+ name: "netdTest",
+ srcs: ["netdTest.c"],
sub_dir: "netd",
}
@@ -687,7 +686,7 @@
"overlay/blue/rro.apk",
"etc/bpf/bpf.o",
"etc/bpf/bpf2.o",
- "etc/bpf/netd/netd_test.o",
+ "etc/bpf/netd/netdTest.o",
})
}
@@ -949,8 +948,10 @@
// mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
// ensureNotContains(t, mylib2Cflags, "-include ")
- // Ensure that genstub is invoked with --apex
- ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"])
+ // Ensure that genstub for platform-provided lib is invoked with --systemapi
+ ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
+ // Ensure that genstub for apex-provided lib is invoked with --apex
+ ensureContains(t, ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex")
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
"lib64/mylib.so",
@@ -1134,8 +1135,8 @@
mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("cc").Args["cFlags"]
ensureNotContains(t, mylib2Cflags, "-include ")
- // Ensure that genstub is invoked with --apex
- ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"])
+ // Ensure that genstub is invoked with --systemapi
+ ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"], "--systemapi")
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
"lib64/mylib.so",
@@ -6151,7 +6152,7 @@
name: "override_myapex",
base: "myapex",
apps: ["override_app"],
- bpfs: ["override_bpf"],
+ bpfs: ["overrideBpf"],
prebuilts: ["override_myetc"],
bootclasspath_fragments: ["override_bootclasspath_fragment"],
systemserverclasspath_fragments: ["override_systemserverclasspath_fragment"],
@@ -6201,8 +6202,8 @@
}
bpf {
- name: "override_bpf",
- srcs: ["override_bpf.c"],
+ name: "overrideBpf",
+ srcs: ["overrideBpf.c"],
}
prebuilt_etc {
@@ -6227,6 +6228,9 @@
name: "mybootclasspath_fragment",
contents: ["bcplib"],
apex_available: ["myapex"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -6241,6 +6245,9 @@
name: "override_bootclasspath_fragment",
contents: ["override_bcplib"],
apex_available: ["myapex"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -6299,7 +6306,7 @@
ensureContains(t, copyCmds, "image.apex/app/override_app@TEST.BUILD_ID/override_app.apk")
ensureNotContains(t, copyCmds, "image.apex/etc/bpf/bpf.o")
- ensureContains(t, copyCmds, "image.apex/etc/bpf/override_bpf.o")
+ ensureContains(t, copyCmds, "image.apex/etc/bpf/overrideBpf.o")
ensureNotContains(t, copyCmds, "image.apex/etc/myetc")
ensureContains(t, copyCmds, "image.apex/etc/override_myetc")
@@ -6333,7 +6340,7 @@
data.Custom(&builder, name, "TARGET_", "", data)
androidMk := builder.String()
ensureContains(t, androidMk, "LOCAL_MODULE := override_app.override_myapex")
- ensureContains(t, androidMk, "LOCAL_MODULE := override_bpf.o.override_myapex")
+ ensureContains(t, androidMk, "LOCAL_MODULE := overrideBpf.o.override_myapex")
ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.override_myapex")
ensureContains(t, androidMk, "LOCAL_MODULE := override_bcplib.override_myapex")
ensureContains(t, androidMk, "LOCAL_MODULE := override_systemserverlib.override_myapex")
@@ -7294,6 +7301,9 @@
apex_available: [
"some-non-updatable-apex",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -7352,6 +7362,9 @@
apex_available: [
"com.android.art.debug",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
apex_key {
@@ -7428,7 +7441,7 @@
return result.TestContext
}
-func TestDuplicateDeapexeresFromPrebuiltApexes(t *testing.T) {
+func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
preparers := android.GroupFixturePreparers(
java.PrepareForTestWithJavaDefaultModules,
PrepareForTestWithApexBuildComponents,
@@ -7497,6 +7510,107 @@
})
}
+func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) {
+ preparers := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithApexBuildComponents,
+ )
+
+ bpBase := `
+ apex_set {
+ name: "com.android.myapex",
+ installable: true,
+ exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+ set: "myapex.apks",
+ }
+
+ apex_set {
+ name: "com.android.myapex_compressed",
+ apex_name: "com.android.myapex",
+ installable: true,
+ exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+ set: "myapex_compressed.apks",
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "my-bootclasspath-fragment",
+ apex_available: [
+ "com.android.myapex",
+ "com.android.myapex_compressed",
+ ],
+ hidden_api: {
+ annotation_flags: "annotation-flags.csv",
+ metadata: "metadata.csv",
+ index: "index.csv",
+ signature_patterns: "signature_patterns.csv",
+ },
+ %s
+ }
+ `
+
+ t.Run("java_import", func(t *testing.T) {
+ result := preparers.RunTestWithBp(t,
+ fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
+ java_import {
+ name: "libfoo",
+ jars: ["libfoo.jar"],
+ apex_available: [
+ "com.android.myapex",
+ "com.android.myapex_compressed",
+ ],
+ }
+ `)
+
+ module := result.Module("libfoo", "android_common_com.android.myapex")
+ usesLibraryDep := module.(java.UsesLibraryDependency)
+ android.AssertPathRelativeToTopEquals(t, "dex jar path",
+ "out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
+ usesLibraryDep.DexJarBuildPath().Path())
+ })
+
+ t.Run("java_sdk_library_import", func(t *testing.T) {
+ result := preparers.RunTestWithBp(t,
+ fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
+ java_sdk_library_import {
+ name: "libfoo",
+ public: {
+ jars: ["libbar.jar"],
+ },
+ apex_available: [
+ "com.android.myapex",
+ "com.android.myapex_compressed",
+ ],
+ compile_dex: true,
+ }
+ `)
+
+ module := result.Module("libfoo", "android_common_com.android.myapex")
+ usesLibraryDep := module.(java.UsesLibraryDependency)
+ android.AssertPathRelativeToTopEquals(t, "dex jar path",
+ "out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
+ usesLibraryDep.DexJarBuildPath().Path())
+ })
+
+ t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) {
+ _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `
+ image_name: "art",
+ contents: ["libfoo"],
+ `)+`
+ java_sdk_library_import {
+ name: "libfoo",
+ public: {
+ jars: ["libbar.jar"],
+ },
+ apex_available: [
+ "com.android.myapex",
+ "com.android.myapex_compressed",
+ ],
+ compile_dex: true,
+ }
+ `)
+ })
+}
+
func TestUpdatable_should_set_min_sdk_version(t *testing.T) {
testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
apex {
@@ -8695,6 +8809,9 @@
name: "mybootclasspathfragment",
contents: ["mybootclasspathlib"],
apex_available: ["myapex"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -9015,6 +9132,9 @@
name: "mybootclasspathfragment",
contents: ["mybootclasspathlib"],
apex_available: ["myapex"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_sdk_library {
@@ -9115,6 +9235,9 @@
name: "mybootclasspathfragment",
contents: ["mybootclasspathlib"],
apex_available: ["myapex"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_sdk_library {
@@ -9334,6 +9457,9 @@
name: "mybootclasspathfragment",
contents: ["myjavalib"],
apex_available: ["myapex"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
name: "myjavalib",
@@ -9419,6 +9545,63 @@
}
}
+func TestApexBuildsAgainstApiSurfaceStubLibraries(t *testing.T) {
+ bp := `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ min_sdk_version: "29",
+ }
+ apex_key {
+ name: "myapex.key",
+ }
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libc"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ }
+ cc_api_library {
+ name: "libc",
+ src: "libc.so",
+ min_sdk_version: "29",
+ recovery_available: true,
+ }
+ api_imports {
+ name: "api_imports",
+ shared_libs: [
+ "libc",
+ ],
+ header_libs: [],
+ }
+ `
+ result := testApex(t, bp)
+
+ hasDep := func(m android.Module, wantDep android.Module) bool {
+ t.Helper()
+ var found bool
+ result.VisitDirectDeps(m, func(dep blueprint.Module) {
+ if dep == wantDep {
+ found = true
+ }
+ })
+ return found
+ }
+
+ libfooApexVariant := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_apex29").Module()
+ libcApexVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared_apex29").Module()
+
+ android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(libfooApexVariant, libcApexVariant))
+
+ // libfoo core variant should be buildable in the same inner tree since
+ // certain mcombo files might build system and apexes in the same inner tree
+ // libfoo core variant should link against source libc
+ libfooCoreVariant := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+ libcCoreVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared").Module()
+ android.AssertBoolEquals(t, "core variant should link against source libc", true, hasDep(libfooCoreVariant, libcCoreVariant))
+}
+
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index ce6b7f7..b298dac 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -110,6 +110,9 @@
apex_available: [
"com.android.art",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
`,
)
@@ -209,6 +212,9 @@
apex_available: [
"com.android.art",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
bootclasspath_fragment {
@@ -220,6 +226,9 @@
module: "art-bootclasspath-fragment",
},
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
`,
)
@@ -361,6 +370,9 @@
apex_available: [
"com.android.art",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
`, contentsInsert(contents))
@@ -853,6 +865,9 @@
apex_available: [
"myapex",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
`)
@@ -959,6 +974,9 @@
apex_available: [
"com.android.art",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
apex {
@@ -1010,6 +1028,9 @@
module: "art-bootclasspath-fragment",
},
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
`)
@@ -1123,6 +1144,9 @@
apex_available: [
"com.android.art",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
apex {
@@ -1175,6 +1199,9 @@
module: "art-bootclasspath-fragment",
},
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
`)
@@ -1282,6 +1309,9 @@
apex_available: [
"com.android.art",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
apex {
@@ -1334,6 +1364,9 @@
module: "art-bootclasspath-fragment",
},
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
`)
diff --git a/apex/bp2build.go b/apex/bp2build.go
new file mode 100644
index 0000000..221ab13
--- /dev/null
+++ b/apex/bp2build.go
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package apex
+
+import (
+ "android/soong/android"
+ "strings"
+)
+
+// This file contains the bp2build integration for the apex package.
+
+// Export constants as Starlark using bp2build to Bazel.
+func BazelApexToolchainVars() string {
+ content := []string{
+ "# GENERATED BY SOONG. DO NOT EDIT.",
+ "default_manifest_version = " + android.DefaultUpdatableModuleVersion, // constants.go is different in every branch.
+ }
+ return strings.Join(content, "\n")
+}
diff --git a/apex/builder.go b/apex/builder.go
index 9119363..f1b1448 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -76,11 +76,12 @@
Command: `rm -f $out && ${jsonmodify} $in ` +
`-a provideNativeLibs ${provideNativeLibs} ` +
`-a requireNativeLibs ${requireNativeLibs} ` +
+ `-se version 0 ${default_version} ` +
`${opt} ` +
`-o $out`,
CommandDeps: []string{"${jsonmodify}"},
Description: "prepare ${out}",
- }, "provideNativeLibs", "requireNativeLibs", "opt")
+ }, "provideNativeLibs", "requireNativeLibs", "default_version", "opt")
stripApexManifestRule = pctx.StaticRule("stripApexManifestRule", blueprint.RuleParams{
Command: `rm -f $out && ${conv_apex_manifest} strip $in -o $out`,
@@ -213,6 +214,7 @@
Args: map[string]string{
"provideNativeLibs": strings.Join(provideNativeLibs, " "),
"requireNativeLibs": strings.Join(requireNativeLibs, " "),
+ "default_version": android.DefaultUpdatableModuleVersion,
"opt": strings.Join(optCommands, " "),
},
})
@@ -547,8 +549,6 @@
outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
- // Figure out if we need to compress the apex.
- compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex && !ctx.Config().UnbundledBuildApps()
if apexType == imageApex {
////////////////////////////////////////////////////////////////////////////////////
@@ -618,7 +618,12 @@
// Create a NOTICE file, and embed it as an asset file in the APEX.
a.htmlGzNotice = android.PathForModuleOut(ctx, "NOTICE.html.gz")
- android.BuildNoticeHtmlOutputFromLicenseMetadata(ctx, a.htmlGzNotice, "", "", unsignedOutputFile.String())
+ android.BuildNoticeHtmlOutputFromLicenseMetadata(
+ ctx, a.htmlGzNotice, "", "",
+ []string{
+ android.PathForModuleInstall(ctx).String() + "/",
+ android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/",
+ })
noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
builder := android.NewRuleBuilder(pctx, ctx)
builder.Command().Text("cp").
@@ -628,10 +633,15 @@
implicitInputs = append(implicitInputs, noticeAssetPath)
optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
- if (moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) && !a.shouldGenerateHashtree()) && !compressionEnabled {
- // Apexes which are supposed to be installed in builtin dirs(/system, etc)
- // don't need hashtree for activation. Therefore, by removing hashtree from
- // apex bundle (filesystem image in it, to be specific), we can save storage.
+ // Apexes which are supposed to be installed in builtin dirs(/system, etc)
+ // don't need hashtree for activation. Therefore, by removing hashtree from
+ // apex bundle (filesystem image in it, to be specific), we can save storage.
+ needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
+ a.shouldGenerateHashtree()
+ if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
+ needHashTree = true
+ }
+ if !needHashTree {
optFlags = append(optFlags, "--no_hashtree")
}
@@ -799,8 +809,9 @@
return
}
- if apexType == imageApex && (compressionEnabled || a.testOnlyShouldForceCompression()) {
- a.isCompressed = true
+ installSuffix := suffix
+ a.setCompression(ctx)
+ if a.isCompressed {
unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+imageCapexSuffix+".unsigned")
compressRule := android.NewRuleBuilder(pctx, ctx)
@@ -828,10 +839,6 @@
Args: args,
})
a.outputFile = signedCompressedOutputFile
- }
-
- installSuffix := suffix
- if a.isCompressed {
installSuffix = imageCapexSuffix
}
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
index 60f18bd..9142eed 100644
--- a/apex/classpath_element_test.go
+++ b/apex/classpath_element_test.go
@@ -88,6 +88,9 @@
"baz",
"quuz",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -134,6 +137,9 @@
contents: [
"bar",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 06c39ee..4b48da8 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -125,6 +125,7 @@
unsupported_packages: [
"bar-unsupported-packages.txt",
],
+ split_packages: ["*"],
},
}
@@ -274,6 +275,9 @@
"baz",
"quuz",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -317,6 +321,9 @@
name: "my-bootclasspath-fragment",
contents: ["bar"],
apex_available: ["myapex"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
apex_key {
@@ -482,6 +489,9 @@
contents: [
"foo", "bar",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
prebuilt_bootclasspath_fragment {
@@ -599,6 +609,9 @@
generate_classpaths_proto: false,
contents: ["foo"],
apex_available: ["myapex"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -656,6 +669,9 @@
contents: [
"foo",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
platform_bootclasspath {
@@ -696,6 +712,9 @@
bootclasspath_fragment {
name: "not-in-apex-fragment",
contents: ["foo"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
platform_bootclasspath {
@@ -746,6 +765,9 @@
name: "apex-fragment",
contents: ["foo", "bar"],
apex_available:[ "myapex" ],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
platform_bootclasspath {
diff --git a/apex/testing.go b/apex/testing.go
index 337c862..69bd73e 100644
--- a/apex/testing.go
+++ b/apex/testing.go
@@ -24,7 +24,6 @@
android.MockFS{
// Needed by apex.
"system/core/rootdir/etc/public.libraries.android.txt": nil,
- "build/soong/scripts/gen_java_usedby_apex.sh": nil,
"build/soong/scripts/gen_ndk_backedby_apex.sh": nil,
// Needed by prebuilt_apex.
"build/soong/scripts/unpack-prebuilt-apex.sh": nil,
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index d580e5a..21526c3 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -86,7 +86,6 @@
},
system_shared_libs: [],
stl: "none",
- notice: "custom_notice",
}
` + vndkLibrariesTxtFiles("current")
diff --git a/bazel/aquery.go b/bazel/aquery.go
index ee09d0b..418b143 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -16,28 +16,32 @@
import (
"crypto/sha256"
+ "encoding/base64"
"encoding/json"
"fmt"
"path/filepath"
"reflect"
- "regexp"
"sort"
"strings"
"github.com/google/blueprint/proptools"
)
+type artifactId int
+type depsetId int
+type pathFragmentId int
+
// artifact contains relevant portions of Bazel's aquery proto, Artifact.
// Represents a single artifact, whether it's a source file or a derived output file.
type artifact struct {
- Id int
- PathFragmentId int
+ Id artifactId
+ PathFragmentId pathFragmentId
}
type pathFragment struct {
- Id int
+ Id pathFragmentId
Label string
- ParentId int
+ ParentId pathFragmentId
}
// KeyValuePair represents Bazel's aquery proto, KeyValuePair.
@@ -63,9 +67,9 @@
// Represents a data structure containing one or more files. Depsets in Bazel are an efficient
// data structure for storing large numbers of file paths.
type depSetOfFiles struct {
- Id int
- DirectArtifactIds []int
- TransitiveDepSetIds []int
+ Id depsetId
+ DirectArtifactIds []artifactId
+ TransitiveDepSetIds []depsetId
}
// action contains relevant portions of Bazel's aquery proto, Action.
@@ -73,11 +77,12 @@
type action struct {
Arguments []string
EnvironmentVariables []KeyValuePair
- InputDepSetIds []int
+ InputDepSetIds []depsetId
Mnemonic string
- OutputIds []int
+ OutputIds []artifactId
TemplateContent string
Substitutions []KeyValuePair
+ FileContents string
}
// actionGraphContainer contains relevant portions of Bazel's aquery proto, ActionGraphContainer.
@@ -105,46 +110,56 @@
// input path string, but not both.
InputDepsetHashes []string
InputPaths []string
+ FileContents string
}
// A helper type for aquery processing which facilitates retrieval of path IDs from their
// less readable Bazel structures (depset and path fragment).
type aqueryArtifactHandler struct {
+ // Switches to true if any depset contains only `bazelToolsDependencySentinel`
+ bazelToolsDependencySentinelNeeded bool
// Maps depset id to AqueryDepset, a representation of depset which is
// post-processed for middleman artifact handling, unhandled artifact
// dropping, content hashing, etc.
- depsetIdToAqueryDepset map[int]AqueryDepset
+ depsetIdToAqueryDepset map[depsetId]AqueryDepset
// Maps content hash to AqueryDepset.
depsetHashToAqueryDepset map[string]AqueryDepset
// depsetIdToArtifactIdsCache is a memoization of depset flattening, because flattening
// may be an expensive operation.
depsetHashToArtifactPathsCache map[string][]string
- // Maps artifact ContentHash to fully expanded path.
- artifactIdToPath map[int]string
+ // Maps artifact ids to fully expanded paths.
+ artifactIdToPath map[artifactId]string
}
// The tokens should be substituted with the value specified here, instead of the
// one returned in 'substitutions' of TemplateExpand action.
-var TemplateActionOverriddenTokens = map[string]string{
+var templateActionOverriddenTokens = map[string]string{
// Uses "python3" for %python_binary% instead of the value returned by aquery
// which is "py3wrapper.sh". See removePy3wrapperScript.
"%python_binary%": "python3",
}
-// This pattern matches the MANIFEST file created for a py_binary target.
-var manifestFilePattern = regexp.MustCompile(".*/.+\\.runfiles/MANIFEST$")
-
// The file name of py3wrapper.sh, which is used by py_binary targets.
const py3wrapperFileName = "/py3wrapper.sh"
-func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler, error) {
- pathFragments := map[int]pathFragment{}
- for _, pathFragment := range aqueryResult.PathFragments {
- pathFragments[pathFragment.Id] = pathFragment
- }
+// A file to be put into depsets that are otherwise empty
+const bazelToolsDependencySentinel = "BAZEL_TOOLS_DEPENDENCY_SENTINEL"
- artifactIdToPath := map[int]string{}
+func indexBy[K comparable, V any](values []V, keyFn func(v V) K) map[K]V {
+ m := map[K]V{}
+ for _, v := range values {
+ m[keyFn(v)] = v
+ }
+ return m
+}
+
+func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler, error) {
+ pathFragments := indexBy(aqueryResult.PathFragments, func(pf pathFragment) pathFragmentId {
+ return pf.Id
+ })
+
+ artifactIdToPath := map[artifactId]string{}
for _, artifact := range aqueryResult.Artifacts {
artifactPath, err := expandPathFragment(artifact.PathFragmentId, pathFragments)
if err != nil {
@@ -155,10 +170,10 @@
// Map middleman artifact ContentHash to input artifact depset ID.
// Middleman artifacts are treated as "substitute" artifacts for mixed builds. For example,
- // if we find a middleman action which has outputs [foo, bar], and output [baz_middleman], then,
+ // if we find a middleman action which has inputs [foo, bar], and output [baz_middleman], then,
// for each other action which has input [baz_middleman], we add [foo, bar] to the inputs for
// that action instead.
- middlemanIdToDepsetIds := map[int][]int{}
+ middlemanIdToDepsetIds := map[artifactId][]depsetId{}
for _, actionEntry := range aqueryResult.Actions {
if actionEntry.Mnemonic == "Middleman" {
for _, outputId := range actionEntry.OutputIds {
@@ -167,19 +182,12 @@
}
}
- // Store all depset IDs to validate all depset links are resolvable.
- depsetIds := map[int]bool{}
- for _, depset := range aqueryResult.DepSetOfFiles {
- depsetIds[depset.Id] = true
- }
-
- depsetIdToDepset := map[int]depSetOfFiles{}
- for _, depset := range aqueryResult.DepSetOfFiles {
- depsetIdToDepset[depset.Id] = depset
- }
+ depsetIdToDepset := indexBy(aqueryResult.DepSetOfFiles, func(d depSetOfFiles) depsetId {
+ return d.Id
+ })
aqueryHandler := aqueryArtifactHandler{
- depsetIdToAqueryDepset: map[int]AqueryDepset{},
+ depsetIdToAqueryDepset: map[depsetId]AqueryDepset{},
depsetHashToAqueryDepset: map[string]AqueryDepset{},
depsetHashToArtifactPathsCache: map[string][]string{},
artifactIdToPath: artifactIdToPath,
@@ -198,12 +206,12 @@
// Ensures that the handler's depsetIdToAqueryDepset map contains an entry for the given
// depset.
-func (a *aqueryArtifactHandler) populateDepsetMaps(depset depSetOfFiles, middlemanIdToDepsetIds map[int][]int, depsetIdToDepset map[int]depSetOfFiles) (AqueryDepset, error) {
+func (a *aqueryArtifactHandler) populateDepsetMaps(depset depSetOfFiles, middlemanIdToDepsetIds map[artifactId][]depsetId, depsetIdToDepset map[depsetId]depSetOfFiles) (AqueryDepset, error) {
if aqueryDepset, containsDepset := a.depsetIdToAqueryDepset[depset.Id]; containsDepset {
return aqueryDepset, nil
}
transitiveDepsetIds := depset.TransitiveDepSetIds
- directArtifactPaths := []string{}
+ var directArtifactPaths []string
for _, artifactId := range depset.DirectArtifactIds {
path, pathExists := a.artifactIdToPath[artifactId]
if !pathExists {
@@ -214,25 +222,20 @@
if depsetsToUse, isMiddleman := middlemanIdToDepsetIds[artifactId]; isMiddleman {
// Swap middleman artifacts with their corresponding depsets and drop the middleman artifacts.
transitiveDepsetIds = append(transitiveDepsetIds, depsetsToUse...)
- } else if strings.HasSuffix(path, py3wrapperFileName) || manifestFilePattern.MatchString(path) {
+ } else if strings.HasSuffix(path, py3wrapperFileName) ||
+ strings.HasPrefix(path, "../bazel_tools") {
// Drop these artifacts.
// See go/python-binary-host-mixed-build for more details.
- // 1) For py3wrapper.sh, there is no action for creating py3wrapper.sh in the aquery output of
- // Bazel py_binary targets, so there is no Ninja build statements generated for creating it.
- // 2) For MANIFEST file, SourceSymlinkManifest action is in aquery output of Bazel py_binary targets,
- // but it doesn't contain sufficient information so no Ninja build statements are generated
- // for creating it.
- // So in mixed build mode, when these two are used as input of some Ninja build statement,
- // since there is no build statement to create them, they should be removed from input paths.
- // TODO(b/197135294): Clean up this custom runfiles handling logic when
- // SourceSymlinkManifest and SymlinkTree actions are supported.
+ // 1) Drop py3wrapper.sh, just use python binary, the launcher script generated by the
+ // TemplateExpandAction handles everything necessary to launch a Pythin application.
+ // 2) ../bazel_tools: they have MODIFY timestamp 10years in the future and would cause the
+ // containing depset to always be considered newer than their outputs.
} else {
- // TODO(b/216194240): Filter out bazel tools.
directArtifactPaths = append(directArtifactPaths, path)
}
}
- childDepsetHashes := []string{}
+ var childDepsetHashes []string
for _, childDepsetId := range transitiveDepsetIds {
childDepset, exists := depsetIdToDepset[childDepsetId]
if !exists {
@@ -244,6 +247,13 @@
}
childDepsetHashes = append(childDepsetHashes, childAqueryDepset.ContentHash)
}
+ if len(directArtifactPaths) == 0 && len(childDepsetHashes) == 0 {
+ // We could omit this depset altogether but that requires cleanup on
+ // transitive dependents.
+ // As a simpler alternative, we use this sentinel file as a dependency.
+ directArtifactPaths = append(directArtifactPaths, bazelToolsDependencySentinel)
+ a.bazelToolsDependencySentinelNeeded = true
+ }
aqueryDepset := AqueryDepset{
ContentHash: depsetContentHash(directArtifactPaths, childDepsetHashes),
DirectArtifacts: directArtifactPaths,
@@ -258,8 +268,8 @@
// input paths contained in these depsets.
// This is a potentially expensive operation, and should not be invoked except
// for actions which need specialized input handling.
-func (a *aqueryArtifactHandler) getInputPaths(depsetIds []int) ([]string, error) {
- inputPaths := []string{}
+func (a *aqueryArtifactHandler) getInputPaths(depsetIds []depsetId) ([]string, error) {
+ var inputPaths []string
for _, inputDepSetId := range depsetIds {
depset := a.depsetIdToAqueryDepset[inputDepSetId]
@@ -291,12 +301,12 @@
a.depsetHashToArtifactPathsCache[depsetHash] = result
return result, nil
} else {
- return nil, fmt.Errorf("undefined input depset hash %d", depsetHash)
+ return nil, fmt.Errorf("undefined input depset hash %s", depsetHash)
}
}
// AqueryBuildStatements returns a slice of BuildStatements and a slice of AqueryDepset
-// which should be registered (and output to a ninja file) to correspond with Bazel's
+// which should be registered (and output to a ninja file) to correspond with Bazel's
// action graph, as described by the given action graph json proto.
// BuildStatements are one-to-one with actions in the given action graph, and AqueryDepsets
// are one-to-one with Bazel's depSetOfFiles objects.
@@ -312,6 +322,13 @@
}
var buildStatements []BuildStatement
+ if aqueryHandler.bazelToolsDependencySentinelNeeded {
+ buildStatements = append(buildStatements, BuildStatement{
+ Command: fmt.Sprintf("touch '%s'", bazelToolsDependencySentinel),
+ OutputPaths: []string{bazelToolsDependencySentinel},
+ Mnemonic: bazelToolsDependencySentinel,
+ })
+ }
for _, actionEntry := range aqueryResult.Actions {
if shouldSkipAction(actionEntry) {
@@ -319,12 +336,14 @@
}
var buildStatement BuildStatement
- if isSymlinkAction(actionEntry) {
+ if actionEntry.isSymlinkAction() {
buildStatement, err = aqueryHandler.symlinkActionBuildStatement(actionEntry)
- } else if isTemplateExpandAction(actionEntry) && len(actionEntry.Arguments) < 1 {
+ } else if actionEntry.isTemplateExpandAction() && len(actionEntry.Arguments) < 1 {
buildStatement, err = aqueryHandler.templateExpandActionBuildStatement(actionEntry)
- } else if isPythonZipperAction(actionEntry) {
- buildStatement, err = aqueryHandler.pythonZipperActionBuildStatement(actionEntry, buildStatements)
+ } else if actionEntry.isFileWriteAction() {
+ buildStatement, err = aqueryHandler.fileWriteActionBuildStatement(actionEntry)
+ } else if actionEntry.isSymlinkTreeAction() {
+ buildStatement, err = aqueryHandler.symlinkTreeActionBuildStatement(actionEntry)
} else if len(actionEntry.Arguments) < 1 {
return nil, nil, fmt.Errorf("received action with no command: [%s]", actionEntry.Mnemonic)
} else {
@@ -338,12 +357,12 @@
}
depsetsByHash := map[string]AqueryDepset{}
- depsets := []AqueryDepset{}
+ var depsets []AqueryDepset
for _, aqueryDepset := range aqueryHandler.depsetIdToAqueryDepset {
if prevEntry, hasKey := depsetsByHash[aqueryDepset.ContentHash]; hasKey {
// Two depsets collide on hash. Ensure that their contents are identical.
if !reflect.DeepEqual(aqueryDepset, prevEntry) {
- return nil, nil, fmt.Errorf("Two different depsets have the same hash: %v, %v", prevEntry, aqueryDepset)
+ return nil, nil, fmt.Errorf("two different depsets have the same hash: %v, %v", prevEntry, aqueryDepset)
}
} else {
depsetsByHash[aqueryDepset.ContentHash] = aqueryDepset
@@ -386,15 +405,15 @@
h := sha256.New()
// Use newline as delimiter, as paths cannot contain newline.
h.Write([]byte(strings.Join(directPaths, "\n")))
- h.Write([]byte(strings.Join(transitiveDepsetHashes, "\n")))
- fullHash := fmt.Sprintf("%016x", h.Sum(nil))
+ h.Write([]byte(strings.Join(transitiveDepsetHashes, "")))
+ fullHash := base64.RawURLEncoding.EncodeToString(h.Sum(nil))
return fullHash
}
-func (aqueryHandler *aqueryArtifactHandler) depsetContentHashes(inputDepsetIds []int) ([]string, error) {
- hashes := []string{}
+func (a *aqueryArtifactHandler) depsetContentHashes(inputDepsetIds []depsetId) ([]string, error) {
+ var hashes []string
for _, depsetId := range inputDepsetIds {
- if aqueryDepset, exists := aqueryHandler.depsetIdToAqueryDepset[depsetId]; !exists {
+ if aqueryDepset, exists := a.depsetIdToAqueryDepset[depsetId]; !exists {
return nil, fmt.Errorf("undefined input depsetId %d", depsetId)
} else {
hashes = append(hashes, aqueryDepset.ContentHash)
@@ -403,13 +422,13 @@
return hashes, nil
}
-func (aqueryHandler *aqueryArtifactHandler) normalActionBuildStatement(actionEntry action) (BuildStatement, error) {
+func (a *aqueryArtifactHandler) normalActionBuildStatement(actionEntry action) (BuildStatement, error) {
command := strings.Join(proptools.ShellEscapeListIncludingSpaces(actionEntry.Arguments), " ")
- inputDepsetHashes, err := aqueryHandler.depsetContentHashes(actionEntry.InputDepSetIds)
+ inputDepsetHashes, err := a.depsetContentHashes(actionEntry.InputDepSetIds)
if err != nil {
return BuildStatement{}, err
}
- outputPaths, depfile, err := aqueryHandler.getOutputPaths(actionEntry)
+ outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
return BuildStatement{}, err
}
@@ -425,56 +444,8 @@
return buildStatement, nil
}
-func (aqueryHandler *aqueryArtifactHandler) pythonZipperActionBuildStatement(actionEntry action, prevBuildStatements []BuildStatement) (BuildStatement, error) {
- inputPaths, err := aqueryHandler.getInputPaths(actionEntry.InputDepSetIds)
- if err != nil {
- return BuildStatement{}, err
- }
- outputPaths, depfile, err := aqueryHandler.getOutputPaths(actionEntry)
- if err != nil {
- return BuildStatement{}, err
- }
-
- if len(inputPaths) < 1 || len(outputPaths) != 1 {
- return BuildStatement{}, fmt.Errorf("Expect 1+ input and 1 output to python zipper action, got: input %q, output %q", inputPaths, outputPaths)
- }
- command := strings.Join(proptools.ShellEscapeListIncludingSpaces(actionEntry.Arguments), " ")
- inputPaths, command = removePy3wrapperScript(inputPaths, command)
- command = addCommandForPyBinaryRunfilesDir(command, inputPaths[0], outputPaths[0])
- // Add the python zip file as input of the corresponding python binary stub script in Ninja build statements.
- // In Ninja build statements, the outputs of dependents of a python binary have python binary stub script as input,
- // which is not sufficient without the python zip file from which runfiles directory is created for py_binary.
- //
- // The following logic relies on that Bazel aquery output returns actions in the order that
- // PythonZipper is after TemplateAction of creating Python binary stub script. If later Bazel doesn't return actions
- // in that order, the following logic might not find the build statement generated for Python binary
- // stub script and the build might fail. So the check of pyBinaryFound is added to help debug in case later Bazel might change aquery output.
- // See go/python-binary-host-mixed-build for more details.
- pythonZipFilePath := outputPaths[0]
- pyBinaryFound := false
- for i, _ := range prevBuildStatements {
- if len(prevBuildStatements[i].OutputPaths) == 1 && prevBuildStatements[i].OutputPaths[0]+".zip" == pythonZipFilePath {
- prevBuildStatements[i].InputPaths = append(prevBuildStatements[i].InputPaths, pythonZipFilePath)
- pyBinaryFound = true
- }
- }
- if !pyBinaryFound {
- return BuildStatement{}, fmt.Errorf("Could not find the correspondinging Python binary stub script of PythonZipper: %q", outputPaths)
- }
-
- buildStatement := BuildStatement{
- Command: command,
- Depfile: depfile,
- OutputPaths: outputPaths,
- InputPaths: inputPaths,
- Env: actionEntry.EnvironmentVariables,
- Mnemonic: actionEntry.Mnemonic,
- }
- return buildStatement, nil
-}
-
-func (aqueryHandler *aqueryArtifactHandler) templateExpandActionBuildStatement(actionEntry action) (BuildStatement, error) {
- outputPaths, depfile, err := aqueryHandler.getOutputPaths(actionEntry)
+func (a *aqueryArtifactHandler) templateExpandActionBuildStatement(actionEntry action) (BuildStatement, error) {
+ outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
return BuildStatement{}, err
}
@@ -489,7 +460,7 @@
// See go/python-binary-host-mixed-build for more details.
command := fmt.Sprintf(`/bin/bash -c 'echo "%[1]s" | sed "s/\\\\n/\\n/g" > %[2]s && chmod a+x %[2]s'`,
escapeCommandlineArgument(expandedTemplateContent), outputPaths[0])
- inputDepsetHashes, err := aqueryHandler.depsetContentHashes(actionEntry.InputDepSetIds)
+ inputDepsetHashes, err := a.depsetContentHashes(actionEntry.InputDepSetIds)
if err != nil {
return BuildStatement{}, err
}
@@ -505,13 +476,54 @@
return buildStatement, nil
}
-func (aqueryHandler *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry action) (BuildStatement, error) {
- outputPaths, depfile, err := aqueryHandler.getOutputPaths(actionEntry)
+func (a *aqueryArtifactHandler) fileWriteActionBuildStatement(actionEntry action) (BuildStatement, error) {
+ outputPaths, _, err := a.getOutputPaths(actionEntry)
+ var depsetHashes []string
+ if err == nil {
+ depsetHashes, err = a.depsetContentHashes(actionEntry.InputDepSetIds)
+ }
+ if err != nil {
+ return BuildStatement{}, err
+ }
+ return BuildStatement{
+ Depfile: nil,
+ OutputPaths: outputPaths,
+ Env: actionEntry.EnvironmentVariables,
+ Mnemonic: actionEntry.Mnemonic,
+ InputDepsetHashes: depsetHashes,
+ FileContents: actionEntry.FileContents,
+ }, nil
+}
+
+func (a *aqueryArtifactHandler) symlinkTreeActionBuildStatement(actionEntry action) (BuildStatement, error) {
+ outputPaths, _, err := a.getOutputPaths(actionEntry)
+ if err != nil {
+ return BuildStatement{}, err
+ }
+ inputPaths, err := a.getInputPaths(actionEntry.InputDepSetIds)
+ if err != nil {
+ return BuildStatement{}, err
+ }
+ if len(inputPaths) != 1 || len(outputPaths) != 1 {
+ return BuildStatement{}, fmt.Errorf("Expect 1 input and 1 output to symlink action, got: input %q, output %q", inputPaths, outputPaths)
+ }
+ // The actual command is generated in bazelSingleton.GenerateBuildActions
+ return BuildStatement{
+ Depfile: nil,
+ OutputPaths: outputPaths,
+ Env: actionEntry.EnvironmentVariables,
+ Mnemonic: actionEntry.Mnemonic,
+ InputPaths: inputPaths,
+ }, nil
+}
+
+func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry action) (BuildStatement, error) {
+ outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
return BuildStatement{}, err
}
- inputPaths, err := aqueryHandler.getInputPaths(actionEntry.InputDepSetIds)
+ inputPaths, err := a.getInputPaths(actionEntry.InputDepSetIds)
if err != nil {
return BuildStatement{}, err
}
@@ -538,9 +550,9 @@
return buildStatement, nil
}
-func (aqueryHandler *aqueryArtifactHandler) getOutputPaths(actionEntry action) (outputPaths []string, depfile *string, err error) {
+func (a *aqueryArtifactHandler) getOutputPaths(actionEntry action) (outputPaths []string, depfile *string, err error) {
for _, outputId := range actionEntry.OutputIds {
- outputPath, exists := aqueryHandler.artifactIdToPath[outputId]
+ outputPath, exists := a.artifactIdToPath[outputId]
if !exists {
err = fmt.Errorf("undefined outputId %d", outputId)
return
@@ -562,10 +574,10 @@
// expandTemplateContent substitutes the tokens in a template.
func expandTemplateContent(actionEntry action) string {
- replacerString := []string{}
+ var replacerString []string
for _, pair := range actionEntry.Substitutions {
value := pair.Value
- if val, ok := TemplateActionOverriddenTokens[pair.Key]; ok {
+ if val, ok := templateActionOverriddenTokens[pair.Key]; ok {
value = val
}
replacerString = append(replacerString, pair.Key, value)
@@ -587,83 +599,45 @@
return replacer.Replace(str)
}
-// removePy3wrapperScript removes py3wrapper.sh from the input paths and command of the action of
-// creating python zip file in mixed build mode. py3wrapper.sh is returned as input by aquery but
-// there is no action returned by aquery for creating it. So in mixed build "python3" is used
-// as the PYTHON_BINARY in python binary stub script, and py3wrapper.sh is not needed and should be
-// removed from input paths and command of creating python zip file.
-// See go/python-binary-host-mixed-build for more details.
-// TODO(b/205879240) remove this after py3wrapper.sh could be created in the mixed build mode.
-func removePy3wrapperScript(inputPaths []string, command string) (newInputPaths []string, newCommand string) {
- // Remove from inputs
- filteredInputPaths := []string{}
- for _, path := range inputPaths {
- if !strings.HasSuffix(path, py3wrapperFileName) {
- filteredInputPaths = append(filteredInputPaths, path)
- }
- }
- newInputPaths = filteredInputPaths
-
- // Remove from command line
- var re = regexp.MustCompile(`\S*` + py3wrapperFileName)
- newCommand = re.ReplaceAllString(command, "")
- return
+func (a action) isSymlinkAction() bool {
+ return a.Mnemonic == "Symlink" || a.Mnemonic == "SolibSymlink" || a.Mnemonic == "ExecutableSymlink"
}
-// addCommandForPyBinaryRunfilesDir adds commands creating python binary runfiles directory.
-// runfiles directory is created by using MANIFEST file and MANIFEST file is the output of
-// SourceSymlinkManifest action is in aquery output of Bazel py_binary targets,
-// but since SourceSymlinkManifest doesn't contain sufficient information
-// so MANIFEST file could not be created, which also blocks the creation of runfiles directory.
-// See go/python-binary-host-mixed-build for more details.
-// TODO(b/197135294) create runfiles directory from MANIFEST file once it can be created from SourceSymlinkManifest action.
-func addCommandForPyBinaryRunfilesDir(oldCommand string, zipperCommandPath, zipFilePath string) string {
- // Unzip the zip file, zipFilePath looks like <python_binary>.zip
- runfilesDirName := zipFilePath[0:len(zipFilePath)-4] + ".runfiles"
- command := fmt.Sprintf("%s x %s -d %s", zipperCommandPath, zipFilePath, runfilesDirName)
- // Create a symbolic link in <python_binary>.runfiles/, which is the expected structure
- // when running the python binary stub script.
- command += fmt.Sprintf(" && ln -sf runfiles/__main__ %s", runfilesDirName)
- return oldCommand + " && " + command
-}
-
-func isSymlinkAction(a action) bool {
- return a.Mnemonic == "Symlink" || a.Mnemonic == "SolibSymlink"
-}
-
-func isTemplateExpandAction(a action) bool {
+func (a action) isTemplateExpandAction() bool {
return a.Mnemonic == "TemplateExpand"
}
-func isPythonZipperAction(a action) bool {
- return a.Mnemonic == "PythonZipper"
+func (a action) isFileWriteAction() bool {
+ return a.Mnemonic == "FileWrite" || a.Mnemonic == "SourceSymlinkManifest"
+}
+
+func (a action) isSymlinkTreeAction() bool {
+ return a.Mnemonic == "SymlinkTree"
}
func shouldSkipAction(a action) bool {
- // TODO(b/180945121): Handle complex symlink actions.
- if a.Mnemonic == "SymlinkTree" || a.Mnemonic == "SourceSymlinkManifest" {
- return true
- }
// Middleman actions are not handled like other actions; they are handled separately as a
// preparatory step so that their inputs may be relayed to actions depending on middleman
// artifacts.
if a.Mnemonic == "Middleman" {
return true
}
+ // PythonZipper is bogus action returned by aquery, ignore it (b/236198693)
+ if a.Mnemonic == "PythonZipper" {
+ return true
+ }
// Skip "Fail" actions, which are placeholder actions designed to always fail.
if a.Mnemonic == "Fail" {
return true
}
- // TODO(b/180946980): Handle FileWrite. The aquery proto currently contains no information
- // about the contents that are written.
- if a.Mnemonic == "FileWrite" {
+ if a.Mnemonic == "BaselineCoverage" {
return true
}
return false
}
-func expandPathFragment(id int, pathFragmentsMap map[int]pathFragment) (string, error) {
- labels := []string{}
+func expandPathFragment(id pathFragmentId, pathFragmentsMap map[pathFragmentId]pathFragment) (string, error) {
+ var labels []string
currId := id
// Only positive IDs are valid for path fragments. An ID of zero indicates a terminal node.
for currId > 0 {
@@ -673,7 +647,7 @@
}
labels = append([]string{currFragment.Label}, labels...)
if currId == currFragment.ParentId {
- return "", fmt.Errorf("Fragment cannot refer to itself as parent %#v", currFragment)
+ return "", fmt.Errorf("fragment cannot refer to itself as parent %#v", currFragment)
}
currId = currFragment.ParentId
}
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 740a1f1..5810364 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -17,6 +17,7 @@
import (
"fmt"
"reflect"
+ "sort"
"testing"
)
@@ -24,28 +25,14 @@
// This input string is retrieved from a real build of bionic-related genrules.
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 6
- }, {
- "id": 3,
- "pathFragmentId": 8
- }, {
- "id": 4,
- "pathFragmentId": 12
- }, {
- "id": 5,
- "pathFragmentId": 19
- }, {
- "id": 6,
- "pathFragmentId": 20
- }, {
- "id": 7,
- "pathFragmentId": 21
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 6 },
+ { "id": 3, "pathFragmentId": 8 },
+ { "id": 4, "pathFragmentId": 12 },
+ { "id": 5, "pathFragmentId": 19 },
+ { "id": 6, "pathFragmentId": 20 },
+ { "id": 7, "pathFragmentId": 21 }],
"actions": [{
"targetId": 1,
"actionKey": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7",
@@ -99,132 +86,48 @@
"outputIds": [7],
"primaryOutputId": 7
}],
- "targets": [{
- "id": 1,
- "label": "@sourceroot//bionic/libc:syscalls-arm",
- "ruleClassId": 1
- }, {
- "id": 2,
- "label": "@sourceroot//bionic/libc:syscalls-x86",
- "ruleClassId": 1
- }, {
- "id": 3,
- "label": "@sourceroot//bionic/libc:syscalls-x86_64",
- "ruleClassId": 1
- }, {
- "id": 4,
- "label": "@sourceroot//bionic/libc:syscalls-arm64",
- "ruleClassId": 1
- }],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2, 3]
- }, {
- "id": 2,
- "directArtifactIds": [1, 2, 3]
- }, {
- "id": 3,
- "directArtifactIds": [1, 2, 3]
- }, {
- "id": 4,
- "directArtifactIds": [1, 2, 3]
- }],
+ "targets": [
+ { "id": 1, "label": "@sourceroot//bionic/libc:syscalls-arm", "ruleClassId": 1 },
+ { "id": 2, "label": "@sourceroot//bionic/libc:syscalls-x86", "ruleClassId": 1 },
+ { "id": 3, "label": "@sourceroot//bionic/libc:syscalls-x86_64", "ruleClassId": 1 },
+ { "id": 4, "label": "@sourceroot//bionic/libc:syscalls-arm64", "ruleClassId": 1 }],
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2, 3] },
+ { "id": 2, "directArtifactIds": [1, 2, 3] },
+ { "id": 3, "directArtifactIds": [1, 2, 3] },
+ { "id": 4, "directArtifactIds": [1, 2, 3] }],
"configuration": [{
"id": 1,
"mnemonic": "k8-fastbuild",
"platformName": "k8",
"checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046"
}],
- "ruleClasses": [{
- "id": 1,
- "name": "genrule"
- }],
- "pathFragments": [{
- "id": 5,
- "label": ".."
- }, {
- "id": 4,
- "label": "sourceroot",
- "parentId": 5
- }, {
- "id": 3,
- "label": "bionic",
- "parentId": 4
- }, {
- "id": 2,
- "label": "libc",
- "parentId": 3
- }, {
- "id": 1,
- "label": "SYSCALLS.TXT",
- "parentId": 2
- }, {
- "id": 7,
- "label": "tools",
- "parentId": 2
- }, {
- "id": 6,
- "label": "gensyscalls.py",
- "parentId": 7
- }, {
- "id": 11,
- "label": "bazel_tools",
- "parentId": 5
- }, {
- "id": 10,
- "label": "tools",
- "parentId": 11
- }, {
- "id": 9,
- "label": "genrule",
- "parentId": 10
- }, {
- "id": 8,
- "label": "genrule-setup.sh",
- "parentId": 9
- }, {
- "id": 18,
- "label": "bazel-out"
- }, {
- "id": 17,
- "label": "sourceroot",
- "parentId": 18
- }, {
- "id": 16,
- "label": "k8-fastbuild",
- "parentId": 17
- }, {
- "id": 15,
- "label": "bin",
- "parentId": 16
- }, {
- "id": 14,
- "label": "bionic",
- "parentId": 15
- }, {
- "id": 13,
- "label": "libc",
- "parentId": 14
- }, {
- "id": 12,
- "label": "syscalls-arm.S",
- "parentId": 13
- }, {
- "id": 19,
- "label": "syscalls-x86.S",
- "parentId": 13
- }, {
- "id": 20,
- "label": "syscalls-x86_64.S",
- "parentId": 13
- }, {
- "id": 21,
- "label": "syscalls-arm64.S",
- "parentId": 13
- }]
+ "ruleClasses": [{ "id": 1, "name": "genrule"}],
+ "pathFragments": [
+ { "id": 5, "label": ".." },
+ { "id": 4, "label": "sourceroot", "parentId": 5 },
+ { "id": 3, "label": "bionic", "parentId": 4 },
+ { "id": 2, "label": "libc", "parentId": 3 },
+ { "id": 1, "label": "SYSCALLS.TXT", "parentId": 2 },
+ { "id": 7, "label": "tools", "parentId": 2 },
+ { "id": 6, "label": "gensyscalls.py", "parentId": 7 },
+ { "id": 11, "label": "bazel_tools", "parentId": 5 },
+ { "id": 10, "label": "tools", "parentId": 11 },
+ { "id": 9, "label": "genrule", "parentId": 10 },
+ { "id": 8, "label": "genrule-setup.sh", "parentId": 9 },
+ { "id": 18, "label": "bazel-out" },
+ { "id": 17, "label": "sourceroot", "parentId": 18 },
+ { "id": 16, "label": "k8-fastbuild", "parentId": 17 },
+ { "id": 15, "label": "bin", "parentId": 16 },
+ { "id": 14, "label": "bionic", "parentId": 15 },
+ { "id": 13, "label": "libc", "parentId": 14 },
+ { "id": 12, "label": "syscalls-arm.S", "parentId": 13 },
+ { "id": 19, "label": "syscalls-x86.S", "parentId": 13 },
+ { "id": 20, "label": "syscalls-x86_64.S", "parentId": 13 },
+ { "id": 21, "label": "syscalls-arm64.S", "parentId": 13 }]
}`
actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
- expectedBuildStatements := []BuildStatement{}
+ var expectedBuildStatements []BuildStatement
for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} {
expectedBuildStatements = append(expectedBuildStatements,
BuildStatement{
@@ -235,7 +138,7 @@
fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S", arch),
},
Env: []KeyValuePair{
- KeyValuePair{Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
+ {Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
},
Mnemonic: "Genrule",
})
@@ -245,7 +148,6 @@
expectedFlattenedInputs := []string{
"../sourceroot/bionic/libc/SYSCALLS.TXT",
"../sourceroot/bionic/libc/tools/gensyscalls.py",
- "../bazel_tools/tools/genrule/genrule-setup.sh",
}
// In this example, each depset should have the same expected inputs.
for _, actualDepset := range actualDepsets {
@@ -259,13 +161,9 @@
func TestInvalidOutputId(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -275,17 +173,11 @@
"outputIds": [3],
"primaryOutputId": 3
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -295,13 +187,9 @@
func TestInvalidInputDepsetIdFromAction(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -311,17 +199,11 @@
"outputIds": [1],
"primaryOutputId": 1
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -331,13 +213,9 @@
func TestInvalidInputDepsetIdFromDepset(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -347,18 +225,11 @@
"outputIds": [1],
"primaryOutputId": 1
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2],
- "transitiveDepSetIds": [42]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2], "transitiveDepSetIds": [42] }],
+ "pathFragments": [
+ { "id": 1, "label": "one"},
+ { "id": 2, "label": "two" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -368,13 +239,9 @@
func TestInvalidInputArtifactId(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -384,17 +251,11 @@
"outputIds": [1],
"primaryOutputId": 1
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 3]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 3] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -404,13 +265,9 @@
func TestInvalidPathFragmentId(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -420,18 +277,11 @@
"outputIds": [1],
"primaryOutputId": 1
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two",
- "parentId": 3
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two", "parentId": 3 }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -441,16 +291,10 @@
func TestDepfiles(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }, {
- "id": 3,
- "pathFragmentId": 3
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 },
+ { "id": 3, "pathFragmentId": 3 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -460,20 +304,12 @@
"outputIds": [2, 3],
"primaryOutputId": 2
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2, 3]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }, {
- "id": 3,
- "label": "two.d"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2, 3] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" },
+ { "id": 3, "label": "two.d" }]
}`
actual, _, err := AqueryBuildStatements([]byte(inputString))
@@ -496,19 +332,11 @@
func TestMultipleDepfiles(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }, {
- "id": 3,
- "pathFragmentId": 3
- }, {
- "id": 4,
- "pathFragmentId": 4
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 },
+ { "id": 3, "pathFragmentId": 3 },
+ { "id": 4, "pathFragmentId": 4 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -522,19 +350,11 @@
"id": 1,
"directArtifactIds": [1, 2, 3, 4]
}],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "two"
- }, {
- "id": 3,
- "label": "two.d"
- }, {
- "id": 4,
- "label": "other.d"
- }]
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "two" },
+ { "id": 3, "label": "two.d" },
+ { "id": 4, "label": "other.d" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -546,70 +366,28 @@
// a single action with many inputs given via a deep depset.
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 7
- }, {
- "id": 3,
- "pathFragmentId": 8
- }, {
- "id": 4,
- "pathFragmentId": 9
- }, {
- "id": 5,
- "pathFragmentId": 10
- }, {
- "id": 6,
- "pathFragmentId": 11
- }, {
- "id": 7,
- "pathFragmentId": 12
- }, {
- "id": 8,
- "pathFragmentId": 13
- }, {
- "id": 9,
- "pathFragmentId": 14
- }, {
- "id": 10,
- "pathFragmentId": 15
- }, {
- "id": 11,
- "pathFragmentId": 16
- }, {
- "id": 12,
- "pathFragmentId": 17
- }, {
- "id": 13,
- "pathFragmentId": 18
- }, {
- "id": 14,
- "pathFragmentId": 19
- }, {
- "id": 15,
- "pathFragmentId": 20
- }, {
- "id": 16,
- "pathFragmentId": 21
- }, {
- "id": 17,
- "pathFragmentId": 22
- }, {
- "id": 18,
- "pathFragmentId": 23
- }, {
- "id": 19,
- "pathFragmentId": 24
- }, {
- "id": 20,
- "pathFragmentId": 25
- }, {
- "id": 21,
- "pathFragmentId": 26
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 7 },
+ { "id": 3, "pathFragmentId": 8 },
+ { "id": 4, "pathFragmentId": 9 },
+ { "id": 5, "pathFragmentId": 10 },
+ { "id": 6, "pathFragmentId": 11 },
+ { "id": 7, "pathFragmentId": 12 },
+ { "id": 8, "pathFragmentId": 13 },
+ { "id": 9, "pathFragmentId": 14 },
+ { "id": 10, "pathFragmentId": 15 },
+ { "id": 11, "pathFragmentId": 16 },
+ { "id": 12, "pathFragmentId": 17 },
+ { "id": 13, "pathFragmentId": 18 },
+ { "id": 14, "pathFragmentId": 19 },
+ { "id": 15, "pathFragmentId": 20 },
+ { "id": 16, "pathFragmentId": 21 },
+ { "id": 17, "pathFragmentId": 22 },
+ { "id": 18, "pathFragmentId": 23 },
+ { "id": 19, "pathFragmentId": 24 },
+ { "id": 20, "pathFragmentId": 25 },
+ { "id": 21, "pathFragmentId": 26 }],
"actions": [{
"targetId": 1,
"actionKey": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50",
@@ -620,134 +398,45 @@
"outputIds": [21],
"primaryOutputId": 21
}],
- "depSetOfFiles": [{
- "id": 3,
- "directArtifactIds": [1, 2, 3, 4, 5]
- }, {
- "id": 4,
- "directArtifactIds": [6, 7, 8, 9, 10]
- }, {
- "id": 2,
- "transitiveDepSetIds": [3, 4],
- "directArtifactIds": [11, 12, 13, 14, 15]
- }, {
- "id": 5,
- "directArtifactIds": [16, 17, 18, 19]
- }, {
- "id": 1,
- "transitiveDepSetIds": [2, 5],
- "directArtifactIds": [20]
- }],
- "pathFragments": [{
- "id": 6,
- "label": "bazel-out"
- }, {
- "id": 5,
- "label": "sourceroot",
- "parentId": 6
- }, {
- "id": 4,
- "label": "k8-fastbuild",
- "parentId": 5
- }, {
- "id": 3,
- "label": "bin",
- "parentId": 4
- }, {
- "id": 2,
- "label": "testpkg",
- "parentId": 3
- }, {
- "id": 1,
- "label": "test_1",
- "parentId": 2
- }, {
- "id": 7,
- "label": "test_2",
- "parentId": 2
- }, {
- "id": 8,
- "label": "test_3",
- "parentId": 2
- }, {
- "id": 9,
- "label": "test_4",
- "parentId": 2
- }, {
- "id": 10,
- "label": "test_5",
- "parentId": 2
- }, {
- "id": 11,
- "label": "test_6",
- "parentId": 2
- }, {
- "id": 12,
- "label": "test_7",
- "parentId": 2
- }, {
- "id": 13,
- "label": "test_8",
- "parentId": 2
- }, {
- "id": 14,
- "label": "test_9",
- "parentId": 2
- }, {
- "id": 15,
- "label": "test_10",
- "parentId": 2
- }, {
- "id": 16,
- "label": "test_11",
- "parentId": 2
- }, {
- "id": 17,
- "label": "test_12",
- "parentId": 2
- }, {
- "id": 18,
- "label": "test_13",
- "parentId": 2
- }, {
- "id": 19,
- "label": "test_14",
- "parentId": 2
- }, {
- "id": 20,
- "label": "test_15",
- "parentId": 2
- }, {
- "id": 21,
- "label": "test_16",
- "parentId": 2
- }, {
- "id": 22,
- "label": "test_17",
- "parentId": 2
- }, {
- "id": 23,
- "label": "test_18",
- "parentId": 2
- }, {
- "id": 24,
- "label": "test_19",
- "parentId": 2
- }, {
- "id": 25,
- "label": "test_root",
- "parentId": 2
- }, {
- "id": 26,
- "label": "test_out",
- "parentId": 2
- }]
+ "depSetOfFiles": [
+ { "id": 3, "directArtifactIds": [1, 2, 3, 4, 5] },
+ { "id": 4, "directArtifactIds": [6, 7, 8, 9, 10] },
+ { "id": 2, "transitiveDepSetIds": [3, 4], "directArtifactIds": [11, 12, 13, 14, 15] },
+ { "id": 5, "directArtifactIds": [16, 17, 18, 19] },
+ { "id": 1, "transitiveDepSetIds": [2, 5], "directArtifactIds": [20] }],
+ "pathFragments": [
+ { "id": 6, "label": "bazel-out" },
+ { "id": 5, "label": "sourceroot", "parentId": 6 },
+ { "id": 4, "label": "k8-fastbuild", "parentId": 5 },
+ { "id": 3, "label": "bin", "parentId": 4 },
+ { "id": 2, "label": "testpkg", "parentId": 3 },
+ { "id": 1, "label": "test_1", "parentId": 2 },
+ { "id": 7, "label": "test_2", "parentId": 2 },
+ { "id": 8, "label": "test_3", "parentId": 2 },
+ { "id": 9, "label": "test_4", "parentId": 2 },
+ { "id": 10, "label": "test_5", "parentId": 2 },
+ { "id": 11, "label": "test_6", "parentId": 2 },
+ { "id": 12, "label": "test_7", "parentId": 2 },
+ { "id": 13, "label": "test_8", "parentId": 2 },
+ { "id": 14, "label": "test_9", "parentId": 2 },
+ { "id": 15, "label": "test_10", "parentId": 2 },
+ { "id": 16, "label": "test_11", "parentId": 2 },
+ { "id": 17, "label": "test_12", "parentId": 2 },
+ { "id": 18, "label": "test_13", "parentId": 2 },
+ { "id": 19, "label": "test_14", "parentId": 2 },
+ { "id": 20, "label": "test_15", "parentId": 2 },
+ { "id": 21, "label": "test_16", "parentId": 2 },
+ { "id": 22, "label": "test_17", "parentId": 2 },
+ { "id": 23, "label": "test_18", "parentId": 2 },
+ { "id": 24, "label": "test_19", "parentId": 2 },
+ { "id": 25, "label": "test_root", "parentId": 2 },
+ { "id": 26,"label": "test_out", "parentId": 2 }]
}`
actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
expectedBuildStatements := []BuildStatement{
- BuildStatement{
+ {
Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
Mnemonic: "Action",
@@ -758,7 +447,7 @@
// Inputs for the action are test_{i} from 1 to 20, and test_root. These inputs
// are given via a deep depset, but the depset is flattened when returned as a
// BuildStatement slice.
- expectedFlattenedInputs := []string{}
+ var expectedFlattenedInputs []string
for i := 1; i < 20; i++ {
expectedFlattenedInputs = append(expectedFlattenedInputs, fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_%d", i))
}
@@ -771,54 +460,130 @@
}
}
+func TestSymlinkTree(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "SymlinkTree",
+ "configurationId": 1,
+ "inputDepSetIds": [1],
+ "outputIds": [2],
+ "primaryOutputId": 2,
+ "executionPlatform": "//build/bazel/platforms:linux_x86_64"
+ }],
+ "pathFragments": [
+ { "id": 1, "label": "foo.manifest" },
+ { "id": 2, "label": "foo.runfiles/MANIFEST" }],
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1] }]
+}
+`
+ actual, _, err := AqueryBuildStatements([]byte(inputString))
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+ assertBuildStatements(t, []BuildStatement{
+ {
+ Command: "",
+ OutputPaths: []string{"foo.runfiles/MANIFEST"},
+ Mnemonic: "SymlinkTree",
+ InputPaths: []string{"foo.manifest"},
+ },
+ }, actual)
+}
+
+func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
+ const inputString = `{
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 10 },
+ { "id": 2, "pathFragmentId": 20 },
+ { "id": 3, "pathFragmentId": 30 },
+ { "id": 4, "pathFragmentId": 40 }],
+ "depSetOfFiles": [{
+ "id": 1111,
+ "directArtifactIds": [3 , 4]
+ }, {
+ "id": 2222,
+ "directArtifactIds": [3]
+ }],
+ "actions": [{
+ "targetId": 100,
+ "actionKey": "x",
+ "inputDepSetIds": [1111, 2222],
+ "mnemonic": "x",
+ "arguments": ["bogus", "command"],
+ "outputIds": [2],
+ "primaryOutputId": 1
+ }],
+ "pathFragments": [
+ { "id": 10, "label": "input" },
+ { "id": 20, "label": "output" },
+ { "id": 30, "label": "dep1", "parentId": 50 },
+ { "id": 40, "label": "dep2", "parentId": 60 },
+ { "id": 50, "label": "bazel_tools", "parentId": 60 },
+ { "id": 60, "label": ".."}
+ ]
+}`
+ actualBuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
+ if len(actualDepsets) != 2 {
+ t.Errorf("expected 1 depset but found %#v", actualDepsets)
+ return
+ }
+ dep2Found := false
+ for _, dep := range flattenDepsets([]string{actualDepsets[0].ContentHash}, actualDepsets) {
+ if dep == "../bazel_tools/dep1" {
+ t.Errorf("dependency %s expected to be removed but still exists", dep)
+ } else if dep == "../dep2" {
+ dep2Found = true
+ }
+ }
+ if !dep2Found {
+ t.Errorf("dependency ../dep2 expected but not found")
+ }
+
+ expectedBuildStatement := BuildStatement{
+ Command: "bogus command",
+ OutputPaths: []string{"output"},
+ Mnemonic: "x",
+ }
+ buildStatementFound := false
+ for _, actualBuildStatement := range actualBuildStatements {
+ if buildStatementEquals(actualBuildStatement, expectedBuildStatement) == "" {
+ buildStatementFound = true
+ break
+ }
+ }
+ if !buildStatementFound {
+ t.Errorf("expected but missing %#v in %#v", expectedBuildStatement, actualBuildStatements)
+ return
+ }
+}
+
func TestMiddlemenAction(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }, {
- "id": 3,
- "pathFragmentId": 3
- }, {
- "id": 4,
- "pathFragmentId": 4
- }, {
- "id": 5,
- "pathFragmentId": 5
- }, {
- "id": 6,
- "pathFragmentId": 6
- }],
- "pathFragments": [{
- "id": 1,
- "label": "middleinput_one"
- }, {
- "id": 2,
- "label": "middleinput_two"
- }, {
- "id": 3,
- "label": "middleman_artifact"
- }, {
- "id": 4,
- "label": "maininput_one"
- }, {
- "id": 5,
- "label": "maininput_two"
- }, {
- "id": 6,
- "label": "output"
- }],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1, 2]
- }, {
- "id": 2,
- "directArtifactIds": [3, 4, 5]
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 },
+ { "id": 3, "pathFragmentId": 3 },
+ { "id": 4, "pathFragmentId": 4 },
+ { "id": 5, "pathFragmentId": 5 },
+ { "id": 6, "pathFragmentId": 6 }],
+ "pathFragments": [
+ { "id": 1, "label": "middleinput_one" },
+ { "id": 2, "label": "middleinput_two" },
+ { "id": 3, "label": "middleman_artifact" },
+ { "id": 4, "label": "maininput_one" },
+ { "id": 5, "label": "maininput_two" },
+ { "id": 6, "label": "output" }],
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1, 2] },
+ { "id": 2, "directArtifactIds": [3, 4, 5] }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -847,8 +612,8 @@
}
expectedDepsetFiles := [][]string{
- []string{"middleinput_one", "middleinput_two"},
- []string{"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"},
+ {"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"},
+ {"middleinput_one", "middleinput_two"},
}
assertFlattenedDepsets(t, actualDepsets, expectedDepsetFiles)
@@ -876,7 +641,7 @@
for _, depset := range allDepsets {
depsetsByHash[depset.ContentHash] = depset
}
- result := []string{}
+ var result []string
for _, depsetId := range depsetHashesToFlatten {
result = append(result, flattenDepset(depsetId, depsetsByHash)...)
}
@@ -886,7 +651,7 @@
// Returns the contents of a given depset in post order.
func flattenDepset(depsetHashToFlatten string, allDepsets map[string]AqueryDepset) []string {
depset := allDepsets[depsetHashToFlatten]
- result := []string{}
+ var result []string
for _, depsetId := range depset.TransitiveDepSetHashes {
result = append(result, flattenDepset(depsetId, allDepsets)...)
}
@@ -897,7 +662,7 @@
func assertFlattenedDepsets(t *testing.T, actualDepsets []AqueryDepset, expectedDepsetFiles [][]string) {
t.Helper()
if len(actualDepsets) != len(expectedDepsetFiles) {
- t.Errorf("Expected %d depsets, but got %d depsets", expectedDepsetFiles, actualDepsets)
+ t.Errorf("Expected %d depsets, but got %d depsets", len(expectedDepsetFiles), len(actualDepsets))
}
for i, actualDepset := range actualDepsets {
actualFlattenedInputs := flattenDepsets([]string{actualDepset.ContentHash}, actualDepsets)
@@ -910,13 +675,9 @@
func TestSimpleSymlink(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 3
- }, {
- "id": 2,
- "pathFragmentId": 5
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 3 },
+ { "id": 2, "pathFragmentId": 5 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -925,30 +686,14 @@
"outputIds": [2],
"primaryOutputId": 2
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "file_subdir",
- "parentId": 1
- }, {
- "id": 3,
- "label": "file",
- "parentId": 2
- }, {
- "id": 4,
- "label": "symlink_subdir",
- "parentId": 1
- }, {
- "id": 5,
- "label": "symlink",
- "parentId": 4
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "file_subdir", "parentId": 1 },
+ { "id": 3, "label": "file", "parentId": 2 },
+ { "id": 4, "label": "symlink_subdir", "parentId": 1 },
+ { "id": 5, "label": "symlink", "parentId": 4 }]
}`
actual, _, err := AqueryBuildStatements([]byte(inputString))
@@ -958,7 +703,7 @@
}
expectedBuildStatements := []BuildStatement{
- BuildStatement{
+ {
Command: "mkdir -p one/symlink_subdir && " +
"rm -f one/symlink_subdir/symlink && " +
"ln -sf $PWD/one/file_subdir/file one/symlink_subdir/symlink",
@@ -974,13 +719,9 @@
func TestSymlinkQuotesPaths(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 3
- }, {
- "id": 2,
- "pathFragmentId": 5
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 3 },
+ { "id": 2, "pathFragmentId": 5 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -989,30 +730,14 @@
"outputIds": [2],
"primaryOutputId": 2
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "one"
- }, {
- "id": 2,
- "label": "file subdir",
- "parentId": 1
- }, {
- "id": 3,
- "label": "file",
- "parentId": 2
- }, {
- "id": 4,
- "label": "symlink subdir",
- "parentId": 1
- }, {
- "id": 5,
- "label": "symlink",
- "parentId": 4
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1] }],
+ "pathFragments": [
+ { "id": 1, "label": "one" },
+ { "id": 2, "label": "file subdir", "parentId": 1 },
+ { "id": 3, "label": "file", "parentId": 2 },
+ { "id": 4, "label": "symlink subdir", "parentId": 1 },
+ { "id": 5, "label": "symlink", "parentId": 4 }]
}`
actual, _, err := AqueryBuildStatements([]byte(inputString))
@@ -1022,7 +747,7 @@
}
expectedBuildStatements := []BuildStatement{
- BuildStatement{
+ {
Command: "mkdir -p 'one/symlink subdir' && " +
"rm -f 'one/symlink subdir/symlink' && " +
"ln -sf $PWD/'one/file subdir/file' 'one/symlink subdir/symlink'",
@@ -1038,16 +763,10 @@
func TestSymlinkMultipleInputs(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }, {
- "id": 3,
- "pathFragmentId": 3
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 },
+ { "id": 3, "pathFragmentId": 3 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -1056,20 +775,11 @@
"outputIds": [3],
"primaryOutputId": 3
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1,2]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "file"
- }, {
- "id": 2,
- "label": "other_file"
- }, {
- "id": 3,
- "label": "symlink"
- }]
+ "depSetOfFiles": [{ "id": 1, "directArtifactIds": [1,2] }],
+ "pathFragments": [
+ { "id": 1, "label": "file" },
+ { "id": 2, "label": "other_file" },
+ { "id": 3, "label": "symlink" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -1079,16 +789,10 @@
func TestSymlinkMultipleOutputs(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }, {
- "id": 2,
- "pathFragmentId": 2
- }, {
- "id": 3,
- "pathFragmentId": 3
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 },
+ { "id": 2, "pathFragmentId": 2 },
+ { "id": 3, "pathFragmentId": 3 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -1097,20 +801,12 @@
"outputIds": [2,3],
"primaryOutputId": 2
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [1]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "file"
- }, {
- "id": 2,
- "label": "symlink"
- }, {
- "id": 3,
- "label": "other_symlink"
- }]
+ "depSetOfFiles": [
+ { "id": 1, "directArtifactIds": [1] }],
+ "pathFragments": [
+ { "id": 1, "label": "file" },
+ { "id": 2, "label": "symlink" },
+ { "id": 3, "label": "other_symlink" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
@@ -1133,18 +829,12 @@
"primaryOutputId": 1,
"executionPlatform": "//build/bazel/platforms:linux_x86_64",
"templateContent": "Test template substitutions: %token1%, %python_binary%",
- "substitutions": [{
- "key": "%token1%",
- "value": "abcd"
- },{
- "key": "%python_binary%",
- "value": "python3"
- }]
+ "substitutions": [
+ { "key": "%token1%", "value": "abcd" },
+ { "key": "%python_binary%", "value": "python3" }]
}],
- "pathFragments": [{
- "id": 1,
- "label": "template_file"
- }]
+ "pathFragments": [
+ { "id": 1, "label": "template_file" }]
}`
actual, _, err := AqueryBuildStatements([]byte(inputString))
@@ -1154,7 +844,7 @@
}
expectedBuildStatements := []BuildStatement{
- BuildStatement{
+ {
Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > template_file && " +
"chmod a+x template_file'",
OutputPaths: []string{"template_file"},
@@ -1167,10 +857,8 @@
func TestTemplateExpandActionNoOutput(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
@@ -1179,291 +867,79 @@
"primaryOutputId": 1,
"executionPlatform": "//build/bazel/platforms:linux_x86_64",
"templateContent": "Test template substitutions: %token1%, %python_binary%",
- "substitutions": [{
- "key": "%token1%",
- "value": "abcd"
- },{
- "key": "%python_binary%",
- "value": "python3"
- }]
+ "substitutions": [
+ { "key": "%token1%", "value": "abcd" },
+ { "key": "%python_binary%", "value": "python3" }]
}],
- "pathFragments": [{
- "id": 1,
- "label": "template_file"
- }]
+ "pathFragments": [
+ { "id": 1, "label": "template_file" }]
}`
_, _, err := AqueryBuildStatements([]byte(inputString))
assertError(t, err, `Expect 1 output to template expand action, got: output []`)
}
-func TestPythonZipperActionSuccess(t *testing.T) {
+func TestFileWrite(t *testing.T) {
const inputString = `
{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- },{
- "id": 2,
- "pathFragmentId": 2
- },{
- "id": 3,
- "pathFragmentId": 3
- },{
- "id": 4,
- "pathFragmentId": 4
- },{
- "id": 5,
- "pathFragmentId": 10
- },{
- "id": 10,
- "pathFragmentId": 20
- }],
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 }],
"actions": [{
"targetId": 1,
"actionKey": "x",
- "mnemonic": "TemplateExpand",
+ "mnemonic": "FileWrite",
"configurationId": 1,
"outputIds": [1],
"primaryOutputId": 1,
"executionPlatform": "//build/bazel/platforms:linux_x86_64",
- "templateContent": "Test template substitutions: %token1%, %python_binary%",
- "substitutions": [{
- "key": "%token1%",
- "value": "abcd"
- },{
- "key": "%python_binary%",
- "value": "python3"
- }]
- },{
- "targetId": 1,
- "actionKey": "x",
- "mnemonic": "PythonZipper",
- "configurationId": 1,
- "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
- "outputIds": [2],
- "inputDepSetIds": [1],
- "primaryOutputId": 2
+ "fileContents": "file data\n"
}],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [4, 3, 5]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "python_binary"
- },{
- "id": 2,
- "label": "python_binary.zip"
- },{
- "id": 3,
- "label": "python_binary.py"
- },{
- "id": 9,
- "label": ".."
- }, {
- "id": 8,
- "label": "bazel_tools",
- "parentId": 9
- }, {
- "id": 7,
- "label": "tools",
- "parentId": 8
- }, {
- "id": 6,
- "label": "zip",
- "parentId": 7
- }, {
- "id": 5,
- "label": "zipper",
- "parentId": 6
- }, {
- "id": 4,
- "label": "zipper",
- "parentId": 5
- },{
- "id": 16,
- "label": "bazel-out"
- },{
- "id": 15,
- "label": "bazel_tools",
- "parentId": 16
- }, {
- "id": 14,
- "label": "k8-fastbuild",
- "parentId": 15
- }, {
- "id": 13,
- "label": "bin",
- "parentId": 14
- }, {
- "id": 12,
- "label": "tools",
- "parentId": 13
- }, {
- "id": 11,
- "label": "python",
- "parentId": 12
- }, {
- "id": 10,
- "label": "py3wrapper.sh",
- "parentId": 11
- },{
- "id": 20,
- "label": "python_binary"
- }]
-}`
+ "pathFragments": [
+ { "id": 1, "label": "foo.manifest" }]
+}
+`
actual, _, err := AqueryBuildStatements([]byte(inputString))
-
if err != nil {
t.Errorf("Unexpected error %q", err)
}
+ assertBuildStatements(t, []BuildStatement{
+ {
+ OutputPaths: []string{"foo.manifest"},
+ Mnemonic: "FileWrite",
+ FileContents: "file data\n",
+ },
+ }, actual)
+}
- expectedBuildStatements := []BuildStatement{
- BuildStatement{
- Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > python_binary && " +
- "chmod a+x python_binary'",
- InputPaths: []string{"python_binary.zip"},
- OutputPaths: []string{"python_binary"},
- Mnemonic: "TemplateExpand",
- },
- BuildStatement{
- Command: "../bazel_tools/tools/zip/zipper/zipper cC python_binary.zip __main__.py=bazel-out/k8-fastbuild/bin/python_binary.temp " +
- "__init__.py= runfiles/__main__/__init__.py= runfiles/__main__/python_binary.py=python_binary.py && " +
- "../bazel_tools/tools/zip/zipper/zipper x python_binary.zip -d python_binary.runfiles && ln -sf runfiles/__main__ python_binary.runfiles",
- InputPaths: []string{"../bazel_tools/tools/zip/zipper/zipper", "python_binary.py"},
- OutputPaths: []string{"python_binary.zip"},
- Mnemonic: "PythonZipper",
- },
+func TestSourceSymlinkManifest(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "pathFragmentId": 1 }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "SourceSymlinkManifest",
+ "configurationId": 1,
+ "outputIds": [1],
+ "primaryOutputId": 1,
+ "executionPlatform": "//build/bazel/platforms:linux_x86_64",
+ "fileContents": "symlink target\n"
+ }],
+ "pathFragments": [
+ { "id": 1, "label": "foo.manifest" }]
+}
+`
+ actual, _, err := AqueryBuildStatements([]byte(inputString))
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
}
- assertBuildStatements(t, expectedBuildStatements, actual)
-}
-
-func TestPythonZipperActionNoInput(t *testing.T) {
- const inputString = `
-{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- },{
- "id": 2,
- "pathFragmentId": 2
- }],
- "actions": [{
- "targetId": 1,
- "actionKey": "x",
- "mnemonic": "PythonZipper",
- "configurationId": 1,
- "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
- "outputIds": [2],
- "primaryOutputId": 2
- }],
- "pathFragments": [{
- "id": 1,
- "label": "python_binary"
- },{
- "id": 2,
- "label": "python_binary.zip"
- }]
-}`
- _, _, err := AqueryBuildStatements([]byte(inputString))
- assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input [], output ["python_binary.zip"]`)
-}
-
-func TestPythonZipperActionNoOutput(t *testing.T) {
- const inputString = `
-{
- "artifacts": [{
- "id": 1,
- "pathFragmentId": 1
- },{
- "id": 2,
- "pathFragmentId": 2
- },{
- "id": 3,
- "pathFragmentId": 3
- },{
- "id": 4,
- "pathFragmentId": 4
- },{
- "id": 5,
- "pathFragmentId": 10
- }],
- "actions": [{
- "targetId": 1,
- "actionKey": "x",
- "mnemonic": "PythonZipper",
- "configurationId": 1,
- "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
- "inputDepSetIds": [1]
- }],
- "depSetOfFiles": [{
- "id": 1,
- "directArtifactIds": [4, 3, 5]
- }],
- "pathFragments": [{
- "id": 1,
- "label": "python_binary"
- },{
- "id": 2,
- "label": "python_binary.zip"
- },{
- "id": 3,
- "label": "python_binary.py"
- },{
- "id": 9,
- "label": ".."
- }, {
- "id": 8,
- "label": "bazel_tools",
- "parentId": 9
- }, {
- "id": 7,
- "label": "tools",
- "parentId": 8
- }, {
- "id": 6,
- "label": "zip",
- "parentId": 7
- }, {
- "id": 5,
- "label": "zipper",
- "parentId": 6
- }, {
- "id": 4,
- "label": "zipper",
- "parentId": 5
- },{
- "id": 16,
- "label": "bazel-out"
- },{
- "id": 15,
- "label": "bazel_tools",
- "parentId": 16
- }, {
- "id": 14,
- "label": "k8-fastbuild",
- "parentId": 15
- }, {
- "id": 13,
- "label": "bin",
- "parentId": 14
- }, {
- "id": 12,
- "label": "tools",
- "parentId": 13
- }, {
- "id": 11,
- "label": "python",
- "parentId": 12
- }, {
- "id": 10,
- "label": "py3wrapper.sh",
- "parentId": 11
- }]
-}`
- _, _, err := AqueryBuildStatements([]byte(inputString))
- assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input ["../bazel_tools/tools/zip/zipper/zipper" "python_binary.py"], output []`)
+ assertBuildStatements(t, []BuildStatement{
+ {
+ OutputPaths: []string{"foo.manifest"},
+ Mnemonic: "SourceSymlinkManifest",
+ },
+ }, actual)
}
func assertError(t *testing.T, err error, expected string) {
@@ -1484,50 +960,54 @@
len(expected), len(actual), expected, actual)
return
}
-ACTUAL_LOOP:
- for _, actualStatement := range actual {
- for _, expectedStatement := range expected {
- if buildStatementEquals(actualStatement, expectedStatement) {
- continue ACTUAL_LOOP
- }
+ type compareFn = func(i int, j int) bool
+ byCommand := func(slice []BuildStatement) compareFn {
+ return func(i int, j int) bool {
+ return slice[i].Command < slice[j].Command
}
- t.Errorf("unexpected build statement %#v.\n expected: %#v",
- actualStatement, expected)
- return
+ }
+ sort.SliceStable(expected, byCommand(expected))
+ sort.SliceStable(actual, byCommand(actual))
+ for i, actualStatement := range actual {
+ expectedStatement := expected[i]
+ if differingField := buildStatementEquals(actualStatement, expectedStatement); differingField != "" {
+ t.Errorf("%s differs\nunexpected build statement %#v.\nexpected: %#v",
+ differingField, actualStatement, expectedStatement)
+ return
+ }
}
}
-func buildStatementEquals(first BuildStatement, second BuildStatement) bool {
+func buildStatementEquals(first BuildStatement, second BuildStatement) string {
if first.Mnemonic != second.Mnemonic {
- return false
+ return "Mnemonic"
}
if first.Command != second.Command {
- return false
+ return "Command"
}
// Ordering is significant for environment variables.
if !reflect.DeepEqual(first.Env, second.Env) {
- return false
+ return "Env"
}
// Ordering is irrelevant for input and output paths, so compare sets.
- if !reflect.DeepEqual(stringSet(first.InputPaths), stringSet(second.InputPaths)) {
- return false
+ if !reflect.DeepEqual(sortedStrings(first.InputPaths), sortedStrings(second.InputPaths)) {
+ return "InputPaths"
}
- if !reflect.DeepEqual(stringSet(first.OutputPaths), stringSet(second.OutputPaths)) {
- return false
+ if !reflect.DeepEqual(sortedStrings(first.OutputPaths), sortedStrings(second.OutputPaths)) {
+ return "OutputPaths"
}
- if !reflect.DeepEqual(stringSet(first.SymlinkPaths), stringSet(second.SymlinkPaths)) {
- return false
+ if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
+ return "SymlinkPaths"
}
if first.Depfile != second.Depfile {
- return false
+ return "Depfile"
}
- return true
+ return ""
}
-func stringSet(stringSlice []string) map[string]struct{} {
- stringMap := make(map[string]struct{})
- for _, s := range stringSlice {
- stringMap[s] = struct{}{}
- }
- return stringMap
+func sortedStrings(stringSlice []string) []string {
+ sorted := make([]string, len(stringSlice))
+ copy(sorted, stringSlice)
+ sort.Strings(sorted)
+ return sorted
}
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 7355ac7..0ab49eb 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -43,6 +43,8 @@
osArchDarwinX86_64 = "darwin_x86_64"
osArchLinuxX86 = "linux_glibc_x86"
osArchLinuxX86_64 = "linux_glibc_x86_64"
+ osArchLinuxMuslArm = "linux_musl_arm"
+ osArchLinuxMuslArm64 = "linux_musl_arm64"
osArchLinuxMuslX86 = "linux_musl_x86"
osArchLinuxMuslX86_64 = "linux_musl_x86_64"
osArchLinuxBionicArm64 = "linux_bionic_arm64"
@@ -101,6 +103,8 @@
osArchDarwinX86_64: "//build/bazel/platforms/os_arch:darwin_x86_64",
osArchLinuxX86: "//build/bazel/platforms/os_arch:linux_glibc_x86",
osArchLinuxX86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
+ osArchLinuxMuslArm: "//build/bazel/platforms/os_arch:linux_musl_arm",
+ osArchLinuxMuslArm64: "//build/bazel/platforms/os_arch:linux_musl_arm64",
osArchLinuxMuslX86: "//build/bazel/platforms/os_arch:linux_musl_x86",
osArchLinuxMuslX86_64: "//build/bazel/platforms/os_arch:linux_musl_x86_64",
osArchLinuxBionicArm64: "//build/bazel/platforms/os_arch:linux_bionic_arm64",
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 5d00b0b..d32e619 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -1,6 +1,7 @@
package cquery
import (
+ "encoding/json"
"fmt"
"strings"
)
@@ -9,6 +10,7 @@
GetOutputFiles = &getOutputFilesRequestType{}
GetPythonBinary = &getPythonBinaryRequestType{}
GetCcInfo = &getCcInfoType{}
+ GetApexInfo = &getApexInfoType{}
)
type CcInfo struct {
@@ -132,7 +134,7 @@
sharedLibraries = []
rootSharedLibraries = []
-shared_info_tag = "@rules_cc//examples:experimental_cc_shared_library.bzl%CcSharedLibraryInfo"
+shared_info_tag = "@_builtins//:common/cc/experimental_cc_shared_library.bzl%CcSharedLibraryInfo"
if shared_info_tag in providers(target):
shared_info = providers(target)[shared_info_tag]
for lib in shared_info.linker_input.libraries:
@@ -179,7 +181,7 @@
const expectedLen = 10
splitString := strings.Split(rawString, "|")
if len(splitString) != expectedLen {
- return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
+ return CcInfo{}, fmt.Errorf("expected %d items, got %q", expectedLen, splitString)
}
outputFilesString := splitString[0]
ccObjectsString := splitString[1]
@@ -215,6 +217,54 @@
}, nil
}
+// Query Bazel for the artifacts generated by the apex modules.
+type getApexInfoType struct{}
+
+// Name returns a string name for this request type. Such request type names must be unique,
+// and must only consist of alphanumeric characters.
+func (g getApexInfoType) Name() string {
+ return "getApexInfo"
+}
+
+// StarlarkFunctionBody returns a starlark function body to process this request type.
+// The returned string is the body of a Starlark function which obtains
+// all request-relevant information about a target and returns a string containing
+// this information. The function should have the following properties:
+// - `target` is the only parameter to this function (a configured target).
+// - The return value must be a string.
+// - The function body should not be indented outside of its own scope.
+func (g getApexInfoType) StarlarkFunctionBody() string {
+ return `info = providers(target)["//build/bazel/rules/apex:apex.bzl%ApexInfo"]
+return "{%s}" % ",".join([
+ json_for_file("signed_output", info.signed_output),
+ json_for_file("unsigned_output", info.unsigned_output),
+ json_for_labels("provides_native_libs", info.provides_native_libs),
+ json_for_labels("requires_native_libs", info.requires_native_libs),
+ json_for_files("bundle_key_pair", info.bundle_key_pair),
+ json_for_files("container_key_pair", info.container_key_pair)
+ ])`
+}
+
+type ApexCqueryInfo struct {
+ SignedOutput string `json:"signed_output"`
+ UnsignedOutput string `json:"unsigned_output"`
+ ProvidesLibs []string `json:"provides_native_libs"`
+ RequiresLibs []string `json:"requires_native_libs"`
+ BundleKeyPair []string `json:"bundle_key_pair"`
+ ContainerKeyPair []string `json:"container_key_pair"`
+}
+
+// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+// The given rawString must correspond to the string output which was created by evaluating the
+// Starlark given in StarlarkFunctionBody.
+func (g getApexInfoType) ParseResult(rawString string) ApexCqueryInfo {
+ var info ApexCqueryInfo
+ if err := json.Unmarshal([]byte(rawString), &info); err != nil {
+ panic(fmt.Errorf("cannot parse cquery result '%s': %s", rawString, err))
+ }
+ return info
+}
+
// splitOrEmpty is a modification of strings.Split() that returns an empty list
// if the given string is empty.
func splitOrEmpty(s string, sep string) []string {
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 606e285..34248ce 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -148,13 +148,13 @@
description: "too few result splits",
input: "|",
expectedOutput: CcInfo{},
- expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", expectedSplits, []string{"", ""}),
+ expectedErrorMessage: fmt.Sprintf("expected %d items, got %q", expectedSplits, []string{"", ""}),
},
{
description: "too many result splits",
input: strings.Repeat("|", expectedSplits+1), // 2 too many
expectedOutput: CcInfo{},
- expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", expectedSplits, make([]string, expectedSplits+2)),
+ expectedErrorMessage: fmt.Sprintf("expected %d items, got %q", expectedSplits, make([]string, expectedSplits+2)),
},
}
for _, tc := range testCases {
@@ -167,3 +167,40 @@
}
}
}
+
+func TestGetApexInfoParseResults(t *testing.T) {
+ testCases := []struct {
+ description string
+ input string
+ expectedOutput ApexCqueryInfo
+ }{
+ {
+ description: "no result",
+ input: "{}",
+ expectedOutput: ApexCqueryInfo{},
+ },
+ {
+ description: "one result",
+ input: `{"signed_output":"my.apex",` +
+ `"unsigned_output":"my.apex.unsigned",` +
+ `"requires_native_libs":["//bionic/libc:libc","//bionic/libdl:libdl"],` +
+ `"bundle_key_pair":["foo.pem","foo.privkey"],` +
+ `"container_key_pair":["foo.x509.pem", "foo.pk8"],` +
+ `"provides_native_libs":[]}`,
+ expectedOutput: ApexCqueryInfo{
+ SignedOutput: "my.apex",
+ UnsignedOutput: "my.apex.unsigned",
+ RequiresLibs: []string{"//bionic/libc:libc", "//bionic/libdl:libdl"},
+ ProvidesLibs: []string{},
+ BundleKeyPair: []string{"foo.pem", "foo.privkey"},
+ ContainerKeyPair: []string{"foo.x509.pem", "foo.pk8"},
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actualOutput := GetApexInfo.ParseResult(tc.input)
+ if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+ t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+ }
+ }
+}
diff --git a/bazel/properties.go b/bazel/properties.go
index f956031..bffd97b 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -94,6 +94,10 @@
return ll.Includes == nil && ll.Excludes == nil
}
+func (ll *LabelList) IsEmpty() bool {
+ return len(ll.Includes) == 0 && len(ll.Excludes) == 0
+}
+
func (ll *LabelList) deepCopy() LabelList {
return LabelList{
Includes: ll.Includes[:],
@@ -409,6 +413,11 @@
return false
}
+// SetValue sets value for the no config axis
+func (ba *BoolAttribute) SetValue(value *bool) {
+ ba.SetSelectValue(NoConfigAxis, "", value)
+}
+
// SetSelectValue sets value for the given axis/config.
func (ba *BoolAttribute) SetSelectValue(axis ConfigurationAxis, config string, value *bool) {
axis.validateConfig(config)
@@ -652,6 +661,11 @@
}
}
+// MakeSingleLabelListAttribute initializes a LabelListAttribute as a non-arch specific list with 1 element, the given Label.
+func MakeSingleLabelListAttribute(value Label) LabelListAttribute {
+ return MakeLabelListAttribute(MakeLabelList([]Label{value}))
+}
+
func (lla *LabelListAttribute) SetValue(list LabelList) {
lla.SetSelectValue(NoConfigAxis, "", list)
}
@@ -946,6 +960,146 @@
return ret
}
+// StringAttribute corresponds to the string Bazel attribute type with
+// support for additional metadata, like configurations.
+type StringAttribute struct {
+ // The base value of the string attribute.
+ Value *string
+
+ // The configured attribute label list Values. Optional
+ // a map of independent configurability axes
+ ConfigurableValues configurableStrings
+}
+
+type configurableStrings map[ConfigurationAxis]stringSelectValues
+
+func (cs configurableStrings) setValueForAxis(axis ConfigurationAxis, config string, str *string) {
+ if cs[axis] == nil {
+ cs[axis] = make(stringSelectValues)
+ }
+ var v = ""
+ if str != nil {
+ v = *str
+ }
+ cs[axis][config] = v
+}
+
+type stringSelectValues map[string]string
+
+// HasConfigurableValues returns true if the attribute contains axis-specific string values.
+func (sa StringAttribute) HasConfigurableValues() bool {
+ for _, selectValues := range sa.ConfigurableValues {
+ if len(selectValues) > 0 {
+ return true
+ }
+ }
+ return false
+}
+
+// SetSelectValue set a value for a bazel select for the given axis, config and value.
+func (sa *StringAttribute) SetSelectValue(axis ConfigurationAxis, config string, str *string) {
+ axis.validateConfig(config)
+ switch axis.configurationType {
+ case noConfig:
+ sa.Value = str
+ case arch, os, osArch, productVariables:
+ if sa.ConfigurableValues == nil {
+ sa.ConfigurableValues = make(configurableStrings)
+ }
+ sa.ConfigurableValues.setValueForAxis(axis, config, str)
+ default:
+ panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
+ }
+}
+
+// SelectValue gets a value for a bazel select for the given axis and config.
+func (sa *StringAttribute) SelectValue(axis ConfigurationAxis, config string) *string {
+ axis.validateConfig(config)
+ switch axis.configurationType {
+ case noConfig:
+ return sa.Value
+ case arch, os, osArch, productVariables:
+ if v, ok := sa.ConfigurableValues[axis][config]; ok {
+ return &v
+ } else {
+ return nil
+ }
+ default:
+ panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
+ }
+}
+
+// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
+func (sa *StringAttribute) SortedConfigurationAxes() []ConfigurationAxis {
+ keys := make([]ConfigurationAxis, 0, len(sa.ConfigurableValues))
+ for k := range sa.ConfigurableValues {
+ keys = append(keys, k)
+ }
+
+ sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
+ return keys
+}
+
+// Collapse reduces the configurable axes of the string attribute to a single axis.
+// This is necessary for final writing to bp2build, as a configurable string
+// attribute can only be comprised by a single select.
+func (sa *StringAttribute) Collapse() error {
+ axisTypes := sa.axisTypes()
+ _, containsOs := axisTypes[os]
+ _, containsArch := axisTypes[arch]
+ _, containsOsArch := axisTypes[osArch]
+ _, containsProductVariables := axisTypes[productVariables]
+ if containsProductVariables {
+ if containsOs || containsArch || containsOsArch {
+ return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
+ }
+ }
+ if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
+ // If a bool attribute has both os and arch configuration axes, the only
+ // way to successfully union their values is to increase the granularity
+ // of the configuration criteria to os_arch.
+ for osType, supportedArchs := range osToArchMap {
+ for _, supportedArch := range supportedArchs {
+ osArch := osArchString(osType, supportedArch)
+ if archOsVal := sa.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
+ // Do nothing, as the arch_os is explicitly defined already.
+ } else {
+ archVal := sa.SelectValue(ArchConfigurationAxis, supportedArch)
+ osVal := sa.SelectValue(OsConfigurationAxis, osType)
+ if osVal != nil && archVal != nil {
+ // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
+ // runs after os mutator.
+ sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
+ } else if osVal != nil && archVal == nil {
+ sa.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
+ } else if osVal == nil && archVal != nil {
+ sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
+ }
+ }
+ }
+ }
+ // All os_arch values are now set. Clear os and arch axes.
+ delete(sa.ConfigurableValues, ArchConfigurationAxis)
+ delete(sa.ConfigurableValues, OsConfigurationAxis)
+ // Verify post-condition; this should never fail, provided no additional
+ // axes are introduced.
+ if len(sa.ConfigurableValues) > 1 {
+ panic(fmt.Errorf("error in collapsing attribute: %#v", sa))
+ }
+ }
+ return nil
+}
+
+func (sa *StringAttribute) axisTypes() map[configurationType]bool {
+ types := map[configurationType]bool{}
+ for k := range sa.ConfigurableValues {
+ if strs := sa.ConfigurableValues[k]; len(strs) > 0 {
+ types[k.configurationType] = true
+ }
+ }
+ return types
+}
+
// StringListAttribute corresponds to the string_list Bazel attribute type with
// support for additional metadata, like configurations.
type StringListAttribute struct {
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index e0ce194..cb25627 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -15,24 +15,27 @@
"conversion.go",
"metrics.go",
"symlink_forest.go",
+ "testing.go",
],
deps: [
"soong-android",
"soong-android-allowlists",
"soong-android-soongconfig",
- "soong-shared",
"soong-apex",
"soong-bazel",
"soong-cc",
"soong-cc-config",
"soong-etc",
"soong-genrule",
+ "soong-linkerconfig",
"soong-python",
"soong-sh",
+ "soong-shared",
"soong-starlark-format",
"soong-ui-metrics",
],
testSrcs: [
+ "aar_conversion_test.go",
"android_app_certificate_conversion_test.go",
"android_app_conversion_test.go",
"apex_conversion_test.go",
@@ -48,22 +51,24 @@
"cc_prebuilt_library_conversion_test.go",
"cc_prebuilt_library_shared_test.go",
"cc_prebuilt_library_static_test.go",
+ "cc_yasm_conversion_test.go",
"conversion_test.go",
"filegroup_conversion_test.go",
"genrule_conversion_test.go",
+ "gensrcs_conversion_test.go",
"java_binary_host_conversion_test.go",
"java_import_conversion_test.go",
"java_library_conversion_test.go",
"java_library_host_conversion_test.go",
"java_plugin_conversion_test.go",
"java_proto_conversion_test.go",
+ "linker_config_conversion_test.go",
"performance_test.go",
"prebuilt_etc_conversion_test.go",
"python_binary_conversion_test.go",
"python_library_conversion_test.go",
"sh_conversion_test.go",
"soong_config_module_type_conversion_test.go",
- "testing.go",
],
pluginFor: [
"soong_build",
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
new file mode 100644
index 0000000..8e7c2b5
--- /dev/null
+++ b/bp2build/aar_conversion_test.go
@@ -0,0 +1,138 @@
+// 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 (
+ "android/soong/android"
+ "android/soong/java"
+ "fmt"
+
+ "testing"
+)
+
+func TestConvertAndroidLibrary(t *testing.T) {
+ t.Helper()
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
+ Description: "Android Library - simple example",
+ ModuleTypeUnderTest: "android_library",
+ ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
+ Filesystem: map[string]string{
+ "lib.java": "",
+ "arm.java": "",
+ "x86.java": "",
+ "res/res.png": "",
+ "manifest/AndroidManifest.xml": "",
+ },
+ Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
+android_library {
+ name: "TestLib",
+ srcs: ["lib.java"],
+ arch: {
+ arm: {
+ srcs: ["arm.java"],
+ },
+ x86: {
+ srcs: ["x86.java"],
+ }
+ },
+ manifest: "manifest/AndroidManifest.xml",
+ static_libs: ["static_lib_dep"],
+ java_version: "7",
+}
+`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget(
+ "android_library",
+ "TestLib",
+ AttrNameToString{
+ "srcs": `["lib.java"] + select({
+ "//build/bazel/platforms/arch:arm": ["arm.java"],
+ "//build/bazel/platforms/arch:x86": ["x86.java"],
+ "//conditions:default": [],
+ })`,
+ "manifest": `"manifest/AndroidManifest.xml"`,
+ "resource_files": `["res/res.png"]`,
+ "deps": `[":static_lib_dep"]`,
+ "exports": `[":static_lib_dep"]`,
+ "javacopts": `["-source 1.7 -target 1.7"]`,
+ }),
+ }})
+}
+
+func TestConvertAndroidLibraryWithNoSources(t *testing.T) {
+ t.Helper()
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
+ Description: "Android Library - modules with deps must have sources",
+ ModuleTypeUnderTest: "android_library",
+ ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
+ Filesystem: map[string]string{
+ "res/res.png": "",
+ "AndroidManifest.xml": "",
+ },
+ Blueprint: simpleModuleDoNotConvertBp2build("android_library", "lib_dep") + `
+android_library {
+ name: "TestLib",
+ srcs: [],
+ manifest: "AndroidManifest.xml",
+ libs: ["lib_dep"],
+}
+`,
+ ExpectedErr: fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."),
+ ExpectedBazelTargets: []string{},
+ })
+}
+
+func TestConvertAndroidLibraryImport(t *testing.T) {
+ t.Helper()
+ RunBp2BuildTestCase(
+ t,
+ func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("android_library", java.AndroidLibraryFactory)
+ },
+ Bp2buildTestCase{
+ Description: "Android Library Import",
+ ModuleTypeUnderTest: "android_library_import",
+ ModuleTypeUnderTestFactory: java.AARImportFactory,
+ Filesystem: map[string]string{
+ "import.aar": "",
+ },
+ // Bazel's aar_import can only export *_import targets, so we expect
+ // only "static_import_dep" in exports, but both "static_lib_dep" and
+ // "static_import_dep" in deps
+ Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") +
+ simpleModuleDoNotConvertBp2build("android_library_import", "static_import_dep") + `
+android_library_import {
+ name: "TestImport",
+ aars: ["import.aar"],
+ static_libs: ["static_lib_dep", "static_import_dep"],
+}
+`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget(
+ "aar_import",
+ "TestImport",
+ AttrNameToString{
+ "aar": `"import.aar"`,
+ "deps": `[
+ ":static_lib_dep",
+ ":static_import_dep",
+ ]`,
+ "exports": `[":static_import_dep"]`,
+ },
+ ),
+ },
+ },
+ )
+}
diff --git a/bp2build/android_app_certificate_conversion_test.go b/bp2build/android_app_certificate_conversion_test.go
index 035a352..0104513 100644
--- a/bp2build/android_app_certificate_conversion_test.go
+++ b/bp2build/android_app_certificate_conversion_test.go
@@ -21,28 +21,28 @@
"testing"
)
-func runAndroidAppCertificateTestCase(t *testing.T, tc bp2buildTestCase) {
+func runAndroidAppCertificateTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, registerAndroidAppCertificateModuleTypes, tc)
+ RunBp2BuildTestCase(t, registerAndroidAppCertificateModuleTypes, tc)
}
func registerAndroidAppCertificateModuleTypes(ctx android.RegistrationContext) {
}
func TestAndroidAppCertificateSimple(t *testing.T) {
- runAndroidAppCertificateTestCase(t, bp2buildTestCase{
- description: "Android app certificate - simple example",
- moduleTypeUnderTest: "android_app_certificate",
- moduleTypeUnderTestFactory: java.AndroidAppCertificateFactory,
- filesystem: map[string]string{},
- blueprint: `
+ runAndroidAppCertificateTestCase(t, Bp2buildTestCase{
+ Description: "Android app certificate - simple example",
+ ModuleTypeUnderTest: "android_app_certificate",
+ ModuleTypeUnderTestFactory: java.AndroidAppCertificateFactory,
+ Filesystem: map[string]string{},
+ Blueprint: `
android_app_certificate {
name: "com.android.apogee.cert",
certificate: "chamber_of_secrets_dir",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("android_app_certificate", "com.android.apogee.cert", attrNameToString{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("android_app_certificate", "com.android.apogee.cert", AttrNameToString{
"certificate": `"chamber_of_secrets_dir"`,
}),
}})
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index a216c9d..a37af12 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -21,33 +21,33 @@
"testing"
)
-func runAndroidAppTestCase(t *testing.T, tc bp2buildTestCase) {
+func runAndroidAppTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, registerAndroidAppModuleTypes, tc)
+ RunBp2BuildTestCase(t, registerAndroidAppModuleTypes, tc)
}
func registerAndroidAppModuleTypes(ctx android.RegistrationContext) {
}
func TestMinimalAndroidApp(t *testing.T) {
- runAndroidAppTestCase(t, bp2buildTestCase{
- description: "Android app - simple example",
- moduleTypeUnderTest: "android_app",
- moduleTypeUnderTestFactory: java.AndroidAppFactory,
- filesystem: map[string]string{
+ runAndroidAppTestCase(t, Bp2buildTestCase{
+ Description: "Android app - simple example",
+ ModuleTypeUnderTest: "android_app",
+ ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+ Filesystem: map[string]string{
"app.java": "",
"res/res.png": "",
"AndroidManifest.xml": "",
},
- blueprint: `
+ Blueprint: `
android_app {
name: "TestApp",
srcs: ["app.java"],
sdk_version: "current",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("android_binary", "TestApp", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("android_binary", "TestApp", AttrNameToString{
"srcs": `["app.java"]`,
"manifest": `"AndroidManifest.xml"`,
"resource_files": `["res/res.png"]`,
@@ -56,17 +56,17 @@
}
func TestAndroidAppAllSupportedFields(t *testing.T) {
- runAndroidAppTestCase(t, bp2buildTestCase{
- description: "Android app - all supported fields",
- moduleTypeUnderTest: "android_app",
- moduleTypeUnderTestFactory: java.AndroidAppFactory,
- filesystem: map[string]string{
+ runAndroidAppTestCase(t, Bp2buildTestCase{
+ Description: "Android app - all supported fields",
+ ModuleTypeUnderTest: "android_app",
+ ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+ Filesystem: map[string]string{
"app.java": "",
"resa/res.png": "",
"resb/res.png": "",
"manifest/AndroidManifest.xml": "",
},
- blueprint: simpleModuleDoNotConvertBp2build("android_app", "static_lib_dep") + `
+ Blueprint: simpleModuleDoNotConvertBp2build("android_app", "static_lib_dep") + `
android_app {
name: "TestApp",
srcs: ["app.java"],
@@ -78,8 +78,8 @@
java_version: "7",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("android_binary", "TestApp", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("android_binary", "TestApp", AttrNameToString{
"srcs": `["app.java"]`,
"manifest": `"manifest/AndroidManifest.xml"`,
"resource_files": `[
@@ -94,17 +94,17 @@
}
func TestAndroidAppArchVariantSrcs(t *testing.T) {
- runAndroidAppTestCase(t, bp2buildTestCase{
- description: "Android app - arch variant srcs",
- moduleTypeUnderTest: "android_app",
- moduleTypeUnderTestFactory: java.AndroidAppFactory,
- filesystem: map[string]string{
+ runAndroidAppTestCase(t, Bp2buildTestCase{
+ Description: "Android app - arch variant srcs",
+ ModuleTypeUnderTest: "android_app",
+ ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+ Filesystem: map[string]string{
"arm.java": "",
"x86.java": "",
"res/res.png": "",
"AndroidManifest.xml": "",
},
- blueprint: `
+ Blueprint: `
android_app {
name: "TestApp",
sdk_version: "current",
@@ -118,8 +118,8 @@
}
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("android_binary", "TestApp", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("android_binary", "TestApp", AttrNameToString{
"srcs": `select({
"//build/bazel/platforms/arch:arm": ["arm.java"],
"//build/bazel/platforms/arch:x86": ["x86.java"],
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index d15dc0c..415e695 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -18,15 +18,16 @@
"android/soong/android"
"android/soong/apex"
"android/soong/cc"
+ "android/soong/etc"
"android/soong/java"
"android/soong/sh"
"testing"
)
-func runApexTestCase(t *testing.T, tc bp2buildTestCase) {
+func runApexTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, registerApexModuleTypes, tc)
+ RunBp2BuildTestCase(t, registerApexModuleTypes, tc)
}
func registerApexModuleTypes(ctx android.RegistrationContext) {
@@ -39,11 +40,12 @@
ctx.RegisterModuleType("apex_key", apex.ApexKeyFactory)
ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+ ctx.RegisterModuleType("prebuilt_etc", etc.PrebuiltEtcFactory)
}
-func runOverrideApexTestCase(t *testing.T, tc bp2buildTestCase) {
+func runOverrideApexTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, registerOverrideApexModuleTypes, tc)
+ RunBp2BuildTestCase(t, registerOverrideApexModuleTypes, tc)
}
func registerOverrideApexModuleTypes(ctx android.RegistrationContext) {
@@ -57,15 +59,16 @@
ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
ctx.RegisterModuleType("apex", apex.BundleFactory)
+ ctx.RegisterModuleType("prebuilt_etc", etc.PrebuiltEtcFactory)
}
func TestApexBundleSimple(t *testing.T) {
- runApexTestCase(t, bp2buildTestCase{
- description: "apex - example with all props, file_context is a module in same Android.bp",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- filesystem: map[string]string{},
- blueprint: `
+ runApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - example with all props, file_context is a module in same Android.bp",
+ ModuleTypeUnderTest: "apex",
+ ModuleTypeUnderTestFactory: apex.BundleFactory,
+ Filesystem: map[string]string{},
+ Blueprint: `
apex_key {
name: "com.android.apogee.key",
public_key: "com.android.apogee.avbpubkey",
@@ -89,13 +92,13 @@
bazel_module: { bp2build_available: false },
}
-cc_library {
- name: "pretend_prebuilt_1",
+prebuilt_etc {
+ name: "prebuilt_1",
bazel_module: { bp2build_available: false },
}
-cc_library {
- name: "pretend_prebuilt_2",
+prebuilt_etc {
+ name: "prebuilt_2",
bazel_module: { bp2build_available: false },
}
@@ -130,13 +133,15 @@
"sh_binary_2",
],
prebuilts: [
- "pretend_prebuilt_1",
- "pretend_prebuilt_2",
+ "prebuilt_1",
+ "prebuilt_2",
],
+ package_name: "com.android.apogee.test.package",
+ logging_parent: "logging.parent",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
"android_manifest": `"ApogeeAndroidManifest.xml"`,
"binaries": `[
":cc_binary_1",
@@ -164,21 +169,23 @@
"//conditions:default": [],
})`,
"prebuilts": `[
- ":pretend_prebuilt_1",
- ":pretend_prebuilt_2",
+ ":prebuilt_1",
+ ":prebuilt_2",
]`,
- "updatable": "False",
- "compressible": "False",
+ "updatable": "False",
+ "compressible": "False",
+ "package_name": `"com.android.apogee.test.package"`,
+ "logging_parent": `"logging.parent"`,
}),
}})
}
func TestApexBundleSimple_fileContextsInAnotherAndroidBp(t *testing.T) {
- runApexTestCase(t, bp2buildTestCase{
- description: "apex - file contexts is a module in another Android.bp",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- filesystem: map[string]string{
+ runApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - file contexts is a module in another Android.bp",
+ ModuleTypeUnderTest: "apex",
+ ModuleTypeUnderTestFactory: apex.BundleFactory,
+ Filesystem: map[string]string{
"a/b/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -189,14 +196,14 @@
}
`,
},
- blueprint: `
+ Blueprint: `
apex {
name: "com.android.apogee",
file_contexts: ":com.android.apogee-file_contexts",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
"file_contexts": `"//a/b:com.android.apogee-file_contexts"`,
"manifest": `"apex_manifest.json"`,
}),
@@ -204,19 +211,19 @@
}
func TestApexBundleSimple_fileContextsIsFile(t *testing.T) {
- runApexTestCase(t, bp2buildTestCase{
- description: "apex - file contexts is a file",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- filesystem: map[string]string{},
- blueprint: `
+ runApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - file contexts is a file",
+ ModuleTypeUnderTest: "apex",
+ ModuleTypeUnderTestFactory: apex.BundleFactory,
+ Filesystem: map[string]string{},
+ Blueprint: `
apex {
name: "com.android.apogee",
file_contexts: "file_contexts_file",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
"file_contexts": `"file_contexts_file"`,
"manifest": `"apex_manifest.json"`,
}),
@@ -224,11 +231,11 @@
}
func TestApexBundleSimple_fileContextsIsNotSpecified(t *testing.T) {
- runApexTestCase(t, bp2buildTestCase{
- description: "apex - file contexts is not specified",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- filesystem: map[string]string{
+ runApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - file contexts is not specified",
+ ModuleTypeUnderTest: "apex",
+ ModuleTypeUnderTestFactory: apex.BundleFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -239,13 +246,13 @@
}
`,
},
- blueprint: `
+ Blueprint: `
apex {
name: "com.android.apogee",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
"manifest": `"apex_manifest.json"`,
}),
@@ -253,11 +260,11 @@
}
func TestApexBundleCompileMultilibBoth(t *testing.T) {
- runApexTestCase(t, bp2buildTestCase{
- description: "apex - example with compile_multilib=both",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- filesystem: map[string]string{
+ runApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - example with compile_multilib=both",
+ ModuleTypeUnderTest: "apex",
+ ModuleTypeUnderTestFactory: apex.BundleFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -266,9 +273,9 @@
}
`,
},
- blueprint: createMultilibBlueprint("both"),
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ Blueprint: createMultilibBlueprint("both"),
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
"native_shared_libs_32": `[
":native_shared_lib_1",
":native_shared_lib_3",
@@ -297,11 +304,11 @@
}
func TestApexBundleCompileMultilibFirst(t *testing.T) {
- runApexTestCase(t, bp2buildTestCase{
- description: "apex - example with compile_multilib=first",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- filesystem: map[string]string{
+ runApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - example with compile_multilib=first",
+ ModuleTypeUnderTest: "apex",
+ ModuleTypeUnderTestFactory: apex.BundleFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -310,9 +317,9 @@
}
`,
},
- blueprint: createMultilibBlueprint("first"),
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ Blueprint: createMultilibBlueprint("first"),
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
"native_shared_libs_32": `select({
"//build/bazel/platforms/arch:arm": [
":native_shared_lib_1",
@@ -346,11 +353,11 @@
}
func TestApexBundleCompileMultilib32(t *testing.T) {
- runApexTestCase(t, bp2buildTestCase{
- description: "apex - example with compile_multilib=32",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- filesystem: map[string]string{
+ runApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - example with compile_multilib=32",
+ ModuleTypeUnderTest: "apex",
+ ModuleTypeUnderTestFactory: apex.BundleFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -359,9 +366,9 @@
}
`,
},
- blueprint: createMultilibBlueprint("32"),
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ Blueprint: createMultilibBlueprint("32"),
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
"native_shared_libs_32": `[
":native_shared_lib_1",
":native_shared_lib_3",
@@ -377,11 +384,11 @@
}
func TestApexBundleCompileMultilib64(t *testing.T) {
- runApexTestCase(t, bp2buildTestCase{
- description: "apex - example with compile_multilib=64",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- filesystem: map[string]string{
+ runApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - example with compile_multilib=64",
+ ModuleTypeUnderTest: "apex",
+ ModuleTypeUnderTestFactory: apex.BundleFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -390,9 +397,9 @@
}
`,
},
- blueprint: createMultilibBlueprint("64"),
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ Blueprint: createMultilibBlueprint("64"),
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
"native_shared_libs_64": `select({
"//build/bazel/platforms/arch:arm64": [
":native_shared_lib_1",
@@ -413,11 +420,11 @@
}
func TestApexBundleDefaultPropertyValues(t *testing.T) {
- runApexTestCase(t, bp2buildTestCase{
- description: "apex - default property values",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- filesystem: map[string]string{
+ runApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - default property values",
+ ModuleTypeUnderTest: "apex",
+ ModuleTypeUnderTestFactory: apex.BundleFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -426,13 +433,13 @@
}
`,
},
- blueprint: `
+ Blueprint: `
apex {
name: "com.android.apogee",
manifest: "apogee_manifest.json",
}
`,
- expectedBazelTargets: []string{makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ ExpectedBazelTargets: []string{makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
"manifest": `"apogee_manifest.json"`,
"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
}),
@@ -440,11 +447,11 @@
}
func TestApexBundleHasBazelModuleProps(t *testing.T) {
- runApexTestCase(t, bp2buildTestCase{
- description: "apex - has bazel module props",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- filesystem: map[string]string{
+ runApexTestCase(t, Bp2buildTestCase{
+ Description: "apex - has bazel module props",
+ ModuleTypeUnderTest: "apex",
+ ModuleTypeUnderTestFactory: apex.BundleFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "apogee-file_contexts",
@@ -453,14 +460,14 @@
}
`,
},
- blueprint: `
+ Blueprint: `
apex {
name: "apogee",
manifest: "manifest.json",
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{makeBazelTarget("apex", "apogee", attrNameToString{
+ ExpectedBazelTargets: []string{makeBazelTarget("apex", "apogee", AttrNameToString{
"manifest": `"manifest.json"`,
"file_contexts": `"//system/sepolicy/apex:apogee-file_contexts"`,
}),
@@ -518,12 +525,12 @@
}
func TestBp2BuildOverrideApex(t *testing.T) {
- runOverrideApexTestCase(t, bp2buildTestCase{
- description: "override_apex",
- moduleTypeUnderTest: "override_apex",
- moduleTypeUnderTestFactory: apex.OverrideApexFactory,
- filesystem: map[string]string{},
- blueprint: `
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{},
+ Blueprint: `
apex_key {
name: "com.android.apogee.key",
public_key: "com.android.apogee.avbpubkey",
@@ -547,13 +554,13 @@
bazel_module: { bp2build_available: false },
}
-cc_library {
- name: "pretend_prebuilt_1",
+prebuilt_etc {
+ name: "prebuilt_1",
bazel_module: { bp2build_available: false },
}
-cc_library {
- name: "pretend_prebuilt_2",
+prebuilt_etc {
+ name: "prebuilt_2",
bazel_module: { bp2build_available: false },
}
@@ -588,8 +595,8 @@
"sh_binary_2",
],
prebuilts: [
- "pretend_prebuilt_1",
- "pretend_prebuilt_2",
+ "prebuilt_1",
+ "prebuilt_2",
],
bazel_module: { bp2build_available: false },
}
@@ -616,8 +623,8 @@
compressible: true,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
"android_manifest": `"ApogeeAndroidManifest.xml"`,
"binaries": `[
":cc_binary_1",
@@ -652,11 +659,11 @@
}
func TestApexBundleSimple_manifestIsEmpty_baseApexOverrideApexInDifferentAndroidBp(t *testing.T) {
- runOverrideApexTestCase(t, bp2buildTestCase{
- description: "override_apex - manifest of base apex is empty, base apex and override_apex is in different Android.bp",
- moduleTypeUnderTest: "override_apex",
- moduleTypeUnderTestFactory: apex.OverrideApexFactory,
- filesystem: map[string]string{
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex - manifest of base apex is empty, base apex and override_apex is in different Android.bp",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -670,14 +677,14 @@
}
`,
},
- blueprint: `
+ Blueprint: `
override_apex {
name: "com.google.android.apogee",
base: ":com.android.apogee",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
"manifest": `"//a/b:apex_manifest.json"`,
}),
@@ -685,11 +692,11 @@
}
func TestApexBundleSimple_manifestIsSet_baseApexOverrideApexInDifferentAndroidBp(t *testing.T) {
- runOverrideApexTestCase(t, bp2buildTestCase{
- description: "override_apex - manifest of base apex is set, base apex and override_apex is in different Android.bp",
- moduleTypeUnderTest: "override_apex",
- moduleTypeUnderTestFactory: apex.OverrideApexFactory,
- filesystem: map[string]string{
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex - manifest of base apex is set, base apex and override_apex is in different Android.bp",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -704,14 +711,14 @@
}
`,
},
- blueprint: `
+ Blueprint: `
override_apex {
name: "com.google.android.apogee",
base: ":com.android.apogee",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
"manifest": `"//a/b:apogee_manifest.json"`,
}),
@@ -719,11 +726,11 @@
}
func TestApexBundleSimple_manifestIsEmpty_baseApexOverrideApexInSameAndroidBp(t *testing.T) {
- runOverrideApexTestCase(t, bp2buildTestCase{
- description: "override_apex - manifest of base apex is empty, base apex and override_apex is in same Android.bp",
- moduleTypeUnderTest: "override_apex",
- moduleTypeUnderTestFactory: apex.OverrideApexFactory,
- filesystem: map[string]string{
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex - manifest of base apex is empty, base apex and override_apex is in same Android.bp",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -731,7 +738,7 @@
bazel_module: { bp2build_available: false },
}`,
},
- blueprint: `
+ Blueprint: `
apex {
name: "com.android.apogee",
bazel_module: { bp2build_available: false },
@@ -742,8 +749,8 @@
base: ":com.android.apogee",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
"manifest": `"apex_manifest.json"`,
}),
@@ -751,11 +758,11 @@
}
func TestApexBundleSimple_manifestIsSet_baseApexOverrideApexInSameAndroidBp(t *testing.T) {
- runOverrideApexTestCase(t, bp2buildTestCase{
- description: "override_apex - manifest of base apex is set, base apex and override_apex is in same Android.bp",
- moduleTypeUnderTest: "override_apex",
- moduleTypeUnderTestFactory: apex.OverrideApexFactory,
- filesystem: map[string]string{
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex - manifest of base apex is set, base apex and override_apex is in same Android.bp",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{
"system/sepolicy/apex/Android.bp": `
filegroup {
name: "com.android.apogee-file_contexts",
@@ -763,7 +770,7 @@
bazel_module: { bp2build_available: false },
}`,
},
- blueprint: `
+ Blueprint: `
apex {
name: "com.android.apogee",
manifest: "apogee_manifest.json",
@@ -775,10 +782,237 @@
base: ":com.android.apogee",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
"manifest": `"apogee_manifest.json"`,
}),
}})
}
+
+func TestApexBundleSimple_packageNameOverride(t *testing.T) {
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex - override package name",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{
+ "system/sepolicy/apex/Android.bp": `
+filegroup {
+ name: "com.android.apogee-file_contexts",
+ srcs: [ "apogee-file_contexts", ],
+ bazel_module: { bp2build_available: false },
+}`,
+ },
+ Blueprint: `
+apex {
+ name: "com.android.apogee",
+ bazel_module: { bp2build_available: false },
+}
+
+override_apex {
+ name: "com.google.android.apogee",
+ base: ":com.android.apogee",
+ package_name: "com.google.android.apogee",
+}
+`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
+ "file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
+ "manifest": `"apex_manifest.json"`,
+ "package_name": `"com.google.android.apogee"`,
+ }),
+ }})
+}
+
+func TestApexBundleSimple_NoPrebuiltsOverride(t *testing.T) {
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex - no override",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{
+ "system/sepolicy/apex/Android.bp": `
+filegroup {
+ name: "com.android.apogee-file_contexts",
+ srcs: [ "apogee-file_contexts", ],
+ bazel_module: { bp2build_available: false },
+}`,
+ },
+ Blueprint: `
+prebuilt_etc {
+ name: "prebuilt_file",
+ bazel_module: { bp2build_available: false },
+}
+
+apex {
+ name: "com.android.apogee",
+ bazel_module: { bp2build_available: false },
+ prebuilts: ["prebuilt_file"]
+}
+
+override_apex {
+ name: "com.google.android.apogee",
+ base: ":com.android.apogee",
+}
+`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
+ "file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
+ "manifest": `"apex_manifest.json"`,
+ "prebuilts": `[":prebuilt_file"]`,
+ }),
+ }})
+}
+
+func TestApexBundleSimple_PrebuiltsOverride(t *testing.T) {
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex - ooverride",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{
+ "system/sepolicy/apex/Android.bp": `
+filegroup {
+ name: "com.android.apogee-file_contexts",
+ srcs: [ "apogee-file_contexts", ],
+ bazel_module: { bp2build_available: false },
+}`,
+ },
+ Blueprint: `
+prebuilt_etc {
+ name: "prebuilt_file",
+ bazel_module: { bp2build_available: false },
+}
+
+prebuilt_etc {
+ name: "prebuilt_file2",
+ bazel_module: { bp2build_available: false },
+}
+
+apex {
+ name: "com.android.apogee",
+ bazel_module: { bp2build_available: false },
+ prebuilts: ["prebuilt_file"]
+}
+
+override_apex {
+ name: "com.google.android.apogee",
+ base: ":com.android.apogee",
+ prebuilts: ["prebuilt_file2"]
+}
+`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
+ "file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
+ "manifest": `"apex_manifest.json"`,
+ "prebuilts": `[":prebuilt_file2"]`,
+ }),
+ }})
+}
+
+func TestApexBundleSimple_PrebuiltsOverrideEmptyList(t *testing.T) {
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex - override with empty list",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{
+ "system/sepolicy/apex/Android.bp": `
+filegroup {
+ name: "com.android.apogee-file_contexts",
+ srcs: [ "apogee-file_contexts", ],
+ bazel_module: { bp2build_available: false },
+}`,
+ },
+ Blueprint: `
+prebuilt_etc {
+ name: "prebuilt_file",
+ bazel_module: { bp2build_available: false },
+}
+
+apex {
+ name: "com.android.apogee",
+ bazel_module: { bp2build_available: false },
+ prebuilts: ["prebuilt_file"]
+}
+
+override_apex {
+ name: "com.google.android.apogee",
+ base: ":com.android.apogee",
+ prebuilts: [],
+}
+`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
+ "file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
+ "manifest": `"apex_manifest.json"`,
+ "prebuilts": `[]`,
+ }),
+ }})
+}
+
+func TestApexBundleSimple_NoLoggingParentOverride(t *testing.T) {
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex - logging_parent - no override",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{
+ "system/sepolicy/apex/Android.bp": `
+filegroup {
+ name: "com.android.apogee-file_contexts",
+ srcs: [ "apogee-file_contexts", ],
+ bazel_module: { bp2build_available: false },
+}`,
+ },
+ Blueprint: `
+apex {
+ name: "com.android.apogee",
+ bazel_module: { bp2build_available: false },
+ logging_parent: "foo.bar.baz",
+}
+
+override_apex {
+ name: "com.google.android.apogee",
+ base: ":com.android.apogee",
+}
+`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
+ "file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
+ "manifest": `"apex_manifest.json"`,
+ "logging_parent": `"foo.bar.baz"`,
+ }),
+ }})
+}
+
+func TestApexBundleSimple_LoggingParentOverride(t *testing.T) {
+ runOverrideApexTestCase(t, Bp2buildTestCase{
+ Description: "override_apex - logging_parent - override",
+ ModuleTypeUnderTest: "override_apex",
+ ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+ Filesystem: map[string]string{
+ "system/sepolicy/apex/Android.bp": `
+filegroup {
+ name: "com.android.apogee-file_contexts",
+ srcs: [ "apogee-file_contexts", ],
+ bazel_module: { bp2build_available: false },
+}`,
+ },
+ Blueprint: `
+apex {
+ name: "com.android.apogee",
+ bazel_module: { bp2build_available: false },
+ logging_parent: "foo.bar.baz",
+}
+
+override_apex {
+ name: "com.google.android.apogee",
+ base: ":com.android.apogee",
+ logging_parent: "foo.bar.baz.override",
+}
+`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
+ "file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
+ "manifest": `"apex_manifest.json"`,
+ "logging_parent": `"foo.bar.baz.override"`,
+ }),
+ }})
+}
diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go
index 1d949901..15bccf7 100644
--- a/bp2build/apex_key_conversion_test.go
+++ b/bp2build/apex_key_conversion_test.go
@@ -21,28 +21,28 @@
"testing"
)
-func runApexKeyTestCase(t *testing.T, tc bp2buildTestCase) {
+func runApexKeyTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, registerApexKeyModuleTypes, tc)
+ RunBp2BuildTestCase(t, registerApexKeyModuleTypes, tc)
}
func registerApexKeyModuleTypes(ctx android.RegistrationContext) {
}
func TestApexKeySimple(t *testing.T) {
- runApexKeyTestCase(t, bp2buildTestCase{
- description: "apex key - simple example",
- moduleTypeUnderTest: "apex_key",
- moduleTypeUnderTestFactory: apex.ApexKeyFactory,
- filesystem: map[string]string{},
- blueprint: `
+ runApexKeyTestCase(t, Bp2buildTestCase{
+ Description: "apex key - simple example",
+ ModuleTypeUnderTest: "apex_key",
+ ModuleTypeUnderTestFactory: apex.ApexKeyFactory,
+ Filesystem: map[string]string{},
+ Blueprint: `
apex_key {
name: "com.android.apogee.key",
public_key: "com.android.apogee.avbpubkey",
private_key: "com.android.apogee.pem",
}
`,
- expectedBazelTargets: []string{makeBazelTarget("apex_key", "com.android.apogee.key", attrNameToString{
+ ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
"private_key": `"com.android.apogee.pem"`,
"public_key": `"com.android.apogee.avbpubkey"`,
}),
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index b0c3899..0e3d2a5 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -29,7 +29,9 @@
func Codegen(ctx *CodegenContext) CodegenMetrics {
// This directory stores BUILD files that could be eventually checked-in.
bp2buildDir := android.PathForOutput(ctx, "bp2build")
- android.RemoveAllOutputDir(bp2buildDir)
+ if err := android.RemoveAllOutputDir(bp2buildDir); err != nil {
+ fmt.Printf("ERROR: Encountered error while cleaning %s: %s", bp2buildDir, err.Error())
+ }
res, errs := GenerateBazelTargets(ctx, true)
if len(errs) > 0 {
@@ -40,7 +42,7 @@
fmt.Printf("ERROR: Encountered %d error(s): \nERROR: %s", len(errs), strings.Join(errMsgs, "\n"))
os.Exit(1)
}
- bp2buildFiles := CreateBazelFiles(nil, res.buildFileToTargets, ctx.mode)
+ bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode)
writeFiles(ctx, bp2buildDir, bp2buildFiles)
soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
@@ -52,7 +54,9 @@
// Get the output directory and create it if it doesn't exist.
func getOrCreateOutputDir(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath {
dirPath := outputDir.Join(ctx, dir)
- android.CreateOutputDirIfNonexistent(dirPath, os.ModePerm)
+ if err := android.CreateOutputDirIfNonexistent(dirPath, os.ModePerm); err != nil {
+ fmt.Printf("ERROR: path %s: %s", dirPath, err.Error())
+ }
return dirPath
}
@@ -60,13 +64,13 @@
func writeFiles(ctx android.PathContext, outputDir android.OutputPath, files []BazelFile) {
for _, f := range files {
p := getOrCreateOutputDir(outputDir, ctx, f.Dir).Join(ctx, f.Basename)
- if err := writeFile(ctx, p, f.Contents); err != nil {
+ if err := writeFile(p, f.Contents); err != nil {
panic(fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err))
}
}
}
-func writeFile(ctx android.PathContext, pathToFile android.OutputPath, content string) error {
+func writeFile(pathToFile android.OutputPath, content string) error {
// These files are made editable to allow users to modify and iterate on them
// in the source tree.
return android.WriteFileToOutputDir(pathToFile, []byte(content), 0644)
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index a96a3fc..242ea1e 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -161,22 +161,22 @@
unconvertedDepMode unconvertedDepsMode
}
-func (c *CodegenContext) Mode() CodegenMode {
- return c.mode
+func (ctx *CodegenContext) Mode() CodegenMode {
+ return ctx.mode
}
// CodegenMode is an enum to differentiate code-generation modes.
type CodegenMode int
const (
- // Bp2Build: generate BUILD files with targets buildable by Bazel directly.
+ // Bp2Build - generate BUILD files with targets buildable by Bazel directly.
//
// This mode is used for the Soong->Bazel build definition conversion.
Bp2Build CodegenMode = iota
- // QueryView: generate BUILD files with targets representing fully mutated
+ // QueryView - generate BUILD files with targets representing fully mutated
// Soong modules, representing the fully configured Soong module graph with
- // variants and dependency endges.
+ // variants and dependency edges.
//
// This mode is used for discovering and introspecting the existing Soong
// module graph.
@@ -320,7 +320,8 @@
// Handle modules with unconverted deps. By default, emit a warning.
if unconvertedDeps := aModule.GetUnconvertedBp2buildDeps(); len(unconvertedDeps) > 0 {
- msg := fmt.Sprintf("%q depends on unconverted modules: %s", m.Name(), strings.Join(unconvertedDeps, ", "))
+ msg := fmt.Sprintf("%s %s:%s depends on unconverted modules: %s",
+ moduleType, bpCtx.ModuleDir(m), m.Name(), strings.Join(unconvertedDeps, ", "))
if ctx.unconvertedDepMode == warnUnconvertedDeps {
metrics.moduleWithUnconvertedDepsMsgs = append(metrics.moduleWithUnconvertedDepsMsgs, msg)
} else if ctx.unconvertedDepMode == errorModulesUnconvertedDeps {
@@ -329,7 +330,8 @@
}
}
if unconvertedDeps := aModule.GetMissingBp2buildDeps(); len(unconvertedDeps) > 0 {
- msg := fmt.Sprintf("%q depends on missing modules: %s", m.Name(), strings.Join(unconvertedDeps, ", "))
+ msg := fmt.Sprintf("%s %s:%s depends on missing modules: %s",
+ moduleType, bpCtx.ModuleDir(m), m.Name(), strings.Join(unconvertedDeps, ", "))
if ctx.unconvertedDepMode == warnUnconvertedDeps {
metrics.moduleWithMissingDepsMsgs = append(metrics.moduleWithMissingDepsMsgs, msg)
} else if ctx.unconvertedDepMode == errorModulesUnconvertedDeps {
@@ -470,13 +472,13 @@
})
}
- for p, _ := range ignoredPropNames {
+ for p := range ignoredPropNames {
delete(props.Attrs, p)
}
attributes := propsToAttributes(props.Attrs)
depLabelList := "[\n"
- for depLabel, _ := range depLabels {
+ for depLabel := range depLabels {
depLabelList += fmt.Sprintf(" %q,\n", depLabel)
}
depLabelList += " ]"
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 0f6e139..1ac7518 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -201,7 +201,7 @@
config := android.TestConfig(buildDir, nil, testCase.bp, nil)
ctx := android.NewTestContext(config)
- ctx.RegisterModuleType("custom", customModuleFactory)
+ ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
ctx.Register()
_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
@@ -229,30 +229,76 @@
}
func TestGenerateBazelTargetModules(t *testing.T) {
- testCases := []bp2buildTestCase{
+ testCases := []Bp2buildTestCase{
{
- description: "string ptr props",
- blueprint: `custom {
+ Description: "string prop empty",
+ Blueprint: `custom {
+ name: "foo",
+ string_literal_prop: "",
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", AttrNameToString{
+ "string_literal_prop": `""`,
+ }),
+ },
+ },
+ {
+ Description: `string prop "PROP"`,
+ Blueprint: `custom {
+ name: "foo",
+ string_literal_prop: "PROP",
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", AttrNameToString{
+ "string_literal_prop": `"PROP"`,
+ }),
+ },
+ },
+ {
+ Description: `string prop arch variant`,
+ Blueprint: `custom {
+ name: "foo",
+ arch: {
+ arm: { string_literal_prop: "ARM" },
+ arm64: { string_literal_prop: "ARM64" },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", AttrNameToString{
+ "string_literal_prop": `select({
+ "//build/bazel/platforms/arch:arm": "ARM",
+ "//build/bazel/platforms/arch:arm64": "ARM64",
+ "//conditions:default": None,
+ })`,
+ }),
+ },
+ },
+ {
+ Description: "string ptr props",
+ Blueprint: `custom {
name: "foo",
string_ptr_prop: "",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("custom", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", AttrNameToString{
"string_ptr_prop": `""`,
}),
},
},
{
- description: "string props",
- blueprint: `custom {
+ Description: "string list props",
+ Blueprint: `custom {
name: "foo",
string_list_prop: ["a", "b"],
string_ptr_prop: "a",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("custom", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", AttrNameToString{
"string_list_prop": `[
"a",
"b",
@@ -262,15 +308,15 @@
},
},
{
- description: "control characters",
- blueprint: `custom {
+ Description: "control characters",
+ Blueprint: `custom {
name: "foo",
string_list_prop: ["\t", "\n"],
string_ptr_prop: "a\t\n\r",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("custom", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", AttrNameToString{
"string_list_prop": `[
"\t",
"\n",
@@ -280,8 +326,8 @@
},
},
{
- description: "handles dep",
- blueprint: `custom {
+ Description: "handles dep",
+ Blueprint: `custom {
name: "has_dep",
arch_paths: [":dep"],
bazel_module: { bp2build_available: true },
@@ -292,31 +338,31 @@
arch_paths: ["abc"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("custom", "dep", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "dep", AttrNameToString{
"arch_paths": `["abc"]`,
}),
- makeBazelTarget("custom", "has_dep", attrNameToString{
+ makeBazelTarget("custom", "has_dep", AttrNameToString{
"arch_paths": `[":dep"]`,
}),
},
},
{
- description: "non-existent dep",
- blueprint: `custom {
+ Description: "non-existent dep",
+ Blueprint: `custom {
name: "has_dep",
arch_paths: [":dep"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("custom", "has_dep", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "has_dep", AttrNameToString{
"arch_paths": `[":dep__BP2BUILD__MISSING__DEP"]`,
}),
},
},
{
- description: "arch-variant srcs",
- blueprint: `custom {
+ Description: "arch-variant srcs",
+ Blueprint: `custom {
name: "arch_paths",
arch: {
x86: { arch_paths: ["x86.txt"] },
@@ -344,8 +390,8 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("custom", "arch_paths", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "arch_paths", AttrNameToString{
"arch_paths": `select({
"//build/bazel/platforms/arch:arm": [
"arm.txt",
@@ -406,8 +452,8 @@
},
},
{
- description: "arch-variant deps",
- blueprint: `custom {
+ Description: "arch-variant deps",
+ Blueprint: `custom {
name: "has_dep",
arch: {
x86: {
@@ -422,11 +468,11 @@
arch_paths: ["abc"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("custom", "dep", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "dep", AttrNameToString{
"arch_paths": `["abc"]`,
}),
- makeBazelTarget("custom", "has_dep", attrNameToString{
+ makeBazelTarget("custom", "has_dep", AttrNameToString{
"arch_paths": `select({
"//build/bazel/platforms/arch:x86": [":dep"],
"//conditions:default": [],
@@ -435,27 +481,27 @@
},
},
{
- description: "embedded props",
- blueprint: `custom {
+ Description: "embedded props",
+ Blueprint: `custom {
name: "embedded_props",
embedded_prop: "abc",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("custom", "embedded_props", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "embedded_props", AttrNameToString{
"embedded_attr": `"abc"`,
}),
},
},
{
- description: "ptr to embedded props",
- blueprint: `custom {
+ Description: "ptr to embedded props",
+ Blueprint: `custom {
name: "ptr_to_embedded_props",
other_embedded_prop: "abc",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("custom", "ptr_to_embedded_props", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("custom", "ptr_to_embedded_props", AttrNameToString{
"other_embedded_attr": `"abc"`,
}),
},
@@ -464,8 +510,8 @@
dir := "."
for _, testCase := range testCases {
- t.Run(testCase.description, func(t *testing.T) {
- config := android.TestConfig(buildDir, nil, testCase.blueprint, nil)
+ t.Run(testCase.Description, func(t *testing.T) {
+ config := android.TestConfig(buildDir, nil, testCase.Blueprint, nil)
ctx := android.NewTestContext(config)
registerCustomModuleForBp2buildConversion(ctx)
@@ -483,10 +529,10 @@
bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
android.FailIfErrored(t, err)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("Expected %d bazel target (%s),\ngot %d (%s)", expectedCount, testCase.expectedBazelTargets, actualCount, bazelTargets)
+ if actualCount, expectedCount := len(bazelTargets), len(testCase.ExpectedBazelTargets); actualCount != expectedCount {
+ t.Errorf("Expected %d bazel target (%s),\ngot %d (%s)", expectedCount, testCase.ExpectedBazelTargets, actualCount, bazelTargets)
} else {
- for i, expectedBazelTarget := range testCase.expectedBazelTargets {
+ for i, expectedBazelTarget := range testCase.ExpectedBazelTargets {
actualBazelTarget := bazelTargets[i]
if actualBazelTarget.content != expectedBazelTarget {
t.Errorf(
@@ -501,6 +547,215 @@
}
}
+func TestBp2buildHostAndDevice(t *testing.T) {
+ testCases := []Bp2buildTestCase{
+ {
+ Description: "host and device, device only",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+ Blueprint: `custom {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
+ },
+ },
+ {
+ Description: "host and device, both",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+ Blueprint: `custom {
+ name: "foo",
+ host_supported: true,
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{}),
+ },
+ },
+ {
+ Description: "host and device, host explicitly disabled",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+ Blueprint: `custom {
+ name: "foo",
+ host_supported: false,
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
+ },
+ },
+ {
+ Description: "host and device, neither",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+ Blueprint: `custom {
+ name: "foo",
+ host_supported: false,
+ device_supported: false,
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
+ "target_compatible_with": `["@platforms//:incompatible"]`,
+ }),
+ },
+ },
+ {
+ Description: "host and device, neither, cannot override with product_var",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+ Blueprint: `custom {
+ name: "foo",
+ host_supported: false,
+ device_supported: false,
+ product_variables: { unbundled_build: { enabled: true } },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
+ "target_compatible_with": `["@platforms//:incompatible"]`,
+ }),
+ },
+ },
+ {
+ Description: "host and device, both, disabled overrided with product_var",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+ Blueprint: `custom {
+ name: "foo",
+ host_supported: true,
+ device_supported: true,
+ enabled: false,
+ product_variables: { unbundled_build: { enabled: true } },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
+ "target_compatible_with": `["//build/bazel/product_variables:unbundled_build"]`,
+ }),
+ },
+ },
+ {
+ Description: "host and device, neither, cannot override with arch enabled",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+ Blueprint: `custom {
+ name: "foo",
+ host_supported: false,
+ device_supported: false,
+ arch: { x86: { enabled: true } },
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
+ "target_compatible_with": `["@platforms//:incompatible"]`,
+ }),
+ },
+ },
+ {
+ Description: "host and device, host only",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+ Blueprint: `custom {
+ name: "foo",
+ host_supported: true,
+ device_supported: false,
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
+ },
+ },
+ {
+ Description: "host only",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostSupported,
+ Blueprint: `custom {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
+ },
+ },
+ {
+ Description: "device only",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryDeviceSupported,
+ Blueprint: `custom {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
+ },
+ },
+ {
+ Description: "host and device default, default",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+ Blueprint: `custom {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{}),
+ },
+ },
+ {
+ Description: "host and device default, device only",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+ Blueprint: `custom {
+ name: "foo",
+ host_supported: false,
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
+ },
+ },
+ {
+ Description: "host and device default, host only",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+ Blueprint: `custom {
+ name: "foo",
+ device_supported: false,
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
+ },
+ },
+ {
+ Description: "host and device default, neither",
+ ModuleTypeUnderTest: "custom",
+ ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+ Blueprint: `custom {
+ name: "foo",
+ host_supported: false,
+ device_supported: false,
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
+ "target_compatible_with": `["@platforms//:incompatible"]`,
+ }),
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.Description, func(t *testing.T) {
+ runBp2BuildTestCaseSimple(t, tc)
+ })
+ }
+}
+
func TestLoadStatements(t *testing.T) {
testCases := []struct {
bazelTargets BazelTargets
@@ -610,6 +865,7 @@
{
bp: `custom {
name: "bar",
+ host_supported: true,
one_to_many_prop: true,
bazel_module: { bp2build_available: true },
}`,
@@ -634,7 +890,7 @@
for _, testCase := range testCases {
config := android.TestConfig(buildDir, nil, testCase.bp, nil)
ctx := android.NewTestContext(config)
- ctx.RegisterModuleType("custom", customModuleFactory)
+ ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
@@ -670,43 +926,43 @@
}
func TestModuleTypeBp2Build(t *testing.T) {
- testCases := []bp2buildTestCase{
+ testCases := []Bp2buildTestCase{
{
- description: "filegroup with does not specify srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: `filegroup {
+ Description: "filegroup with does not specify srcs",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: `filegroup {
name: "fg_foo",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
},
},
{
- description: "filegroup with no srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: `filegroup {
+ Description: "filegroup with no srcs",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: `filegroup {
name: "fg_foo",
srcs: [],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
},
},
{
- description: "filegroup with srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: `filegroup {
+ Description: "filegroup with srcs",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: `filegroup {
name: "fg_foo",
srcs: ["a", "b"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
"srcs": `[
"a",
"b",
@@ -715,32 +971,32 @@
},
},
{
- description: "filegroup with excludes srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: `filegroup {
+ Description: "filegroup with excludes srcs",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: `filegroup {
name: "fg_foo",
srcs: ["a", "b"],
exclude_srcs: ["a"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
"srcs": `["b"]`,
}),
},
},
{
- description: "filegroup with glob",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: `filegroup {
+ Description: "filegroup with glob",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: `filegroup {
name: "fg_foo",
srcs: ["**/*.txt"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
"srcs": `[
"other/a.txt",
"other/b.txt",
@@ -748,7 +1004,7 @@
]`,
}),
},
- filesystem: map[string]string{
+ Filesystem: map[string]string{
"other/a.txt": "",
"other/b.txt": "",
"other/subdir/a.txt": "",
@@ -756,11 +1012,11 @@
},
},
{
- description: "filegroup with glob in subdir",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- dir: "other",
- filesystem: map[string]string{
+ Description: "filegroup with glob in subdir",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Dir: "other",
+ Filesystem: map[string]string{
"other/Android.bp": `filegroup {
name: "fg_foo",
srcs: ["**/*.txt"],
@@ -771,8 +1027,8 @@
"other/subdir/a.txt": "",
"other/file": "",
},
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
"srcs": `[
"a.txt",
"b.txt",
@@ -782,10 +1038,10 @@
},
},
{
- description: "depends_on_other_dir_module",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: `filegroup {
+ Description: "depends_on_other_dir_module",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: `filegroup {
name: "fg_foo",
srcs: [
":foo",
@@ -793,15 +1049,15 @@
],
bazel_module: { bp2build_available: true },
}`,
- filesystem: map[string]string{
+ Filesystem: map[string]string{
"other/Android.bp": `filegroup {
name: "foo",
srcs: ["a", "b"],
bazel_module: { bp2build_available: true },
}`,
},
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
"srcs": `[
"//other:foo",
"c",
@@ -810,11 +1066,11 @@
},
},
{
- description: "depends_on_other_unconverted_module_error",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- unconvertedDepsMode: errorModulesUnconvertedDeps,
- blueprint: `filegroup {
+ Description: "depends_on_other_unconverted_module_error",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ UnconvertedDepsMode: errorModulesUnconvertedDeps,
+ Blueprint: `filegroup {
name: "foobar",
srcs: [
":foo",
@@ -822,8 +1078,8 @@
],
bazel_module: { bp2build_available: true },
}`,
- expectedErr: fmt.Errorf(`"foobar" depends on unconverted modules: foo`),
- filesystem: map[string]string{
+ ExpectedErr: fmt.Errorf(`filegroup .:foobar depends on unconverted modules: foo`),
+ Filesystem: map[string]string{
"other/Android.bp": `filegroup {
name: "foo",
srcs: ["a", "b"],
@@ -833,8 +1089,8 @@
}
for _, testCase := range testCases {
- t.Run(testCase.description, func(t *testing.T) {
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, testCase)
+ t.Run(testCase.Description, func(t *testing.T) {
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, testCase)
})
}
}
@@ -884,7 +1140,7 @@
{
description: "generates more than 1 target if needed",
moduleTypeUnderTest: "custom",
- moduleTypeUnderTestFactory: customModuleFactory,
+ moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
bp: `custom {
name: "foo",
one_to_many_prop: true,
@@ -1034,27 +1290,27 @@
}
func TestCombineBuildFilesBp2buildTargets(t *testing.T) {
- testCases := []bp2buildTestCase{
+ testCases := []Bp2buildTestCase{
{
- description: "filegroup bazel_module.label",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: `filegroup {
+ Description: "filegroup bazel_module.label",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: `filegroup {
name: "fg_foo",
bazel_module: { label: "//other:fg_foo" },
}`,
- expectedBazelTargets: []string{
+ ExpectedBazelTargets: []string{
`// BUILD file`,
},
- filesystem: map[string]string{
+ Filesystem: map[string]string{
"other/BUILD.bazel": `// BUILD file`,
},
},
{
- description: "multiple bazel_module.label same BUILD",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: `filegroup {
+ Description: "multiple bazel_module.label same BUILD",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: `filegroup {
name: "fg_foo",
bazel_module: { label: "//other:fg_foo" },
}
@@ -1063,20 +1319,20 @@
name: "foo",
bazel_module: { label: "//other:foo" },
}`,
- expectedBazelTargets: []string{
+ ExpectedBazelTargets: []string{
`// BUILD file`,
},
- filesystem: map[string]string{
+ Filesystem: map[string]string{
"other/BUILD.bazel": `// BUILD file`,
},
},
{
- description: "filegroup bazel_module.label and bp2build in subdir",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- dir: "other",
- blueprint: ``,
- filesystem: map[string]string{
+ Description: "filegroup bazel_module.label and bp2build in subdir",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Dir: "other",
+ Blueprint: ``,
+ Filesystem: map[string]string{
"other/Android.bp": `filegroup {
name: "fg_foo",
bazel_module: {
@@ -1091,20 +1347,20 @@
}`,
"other/BUILD.bazel": `// definition for fg_bar`,
},
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
`// definition for fg_bar`,
},
},
{
- description: "filegroup bazel_module.label and filegroup bp2build",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
+ Description: "filegroup bazel_module.label and filegroup bp2build",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
- filesystem: map[string]string{
+ Filesystem: map[string]string{
"other/BUILD.bazel": `// BUILD file`,
},
- blueprint: `filegroup {
+ Blueprint: `filegroup {
name: "fg_foo",
bazel_module: {
label: "//other:fg_foo",
@@ -1117,8 +1373,8 @@
bp2build_available: true,
},
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_bar", map[string]string{}),
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_bar", map[string]string{}),
`// BUILD file`,
},
},
@@ -1126,20 +1382,20 @@
dir := "."
for _, testCase := range testCases {
- t.Run(testCase.description, func(t *testing.T) {
+ t.Run(testCase.Description, func(t *testing.T) {
fs := make(map[string][]byte)
toParse := []string{
"Android.bp",
}
- for f, content := range testCase.filesystem {
+ for f, content := range testCase.Filesystem {
if strings.HasSuffix(f, "Android.bp") {
toParse = append(toParse, f)
}
fs[f] = []byte(content)
}
- config := android.TestConfig(buildDir, nil, testCase.blueprint, fs)
+ config := android.TestConfig(buildDir, nil, testCase.Blueprint, fs)
ctx := android.NewTestContext(config)
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+ ctx.RegisterModuleType(testCase.ModuleTypeUnderTest, testCase.ModuleTypeUnderTestFactory)
ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, toParse)
@@ -1152,15 +1408,15 @@
}
checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
+ if testCase.Dir != "" {
+ checkDir = testCase.Dir
}
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
android.FailIfErrored(t, err)
bazelTargets.sort()
actualCount := len(bazelTargets)
- expectedCount := len(testCase.expectedBazelTargets)
+ expectedCount := len(testCase.ExpectedBazelTargets)
if actualCount != expectedCount {
t.Errorf("Expected %d bazel target, got %d\n%s", expectedCount, actualCount, bazelTargets)
}
@@ -1169,7 +1425,7 @@
}
for i, target := range bazelTargets {
actualContent := target.content
- expectedContent := testCase.expectedBazelTargets[i]
+ expectedContent := testCase.ExpectedBazelTargets[i]
if expectedContent != actualContent {
t.Errorf(
"Expected generated Bazel target to be '%s', got '%s'",
@@ -1183,18 +1439,18 @@
}
func TestGlobExcludeSrcs(t *testing.T) {
- testCases := []bp2buildTestCase{
+ testCases := []Bp2buildTestCase{
{
- description: "filegroup top level exclude_srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: `filegroup {
+ Description: "filegroup top level exclude_srcs",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: `filegroup {
name: "fg_foo",
srcs: ["**/*.txt"],
exclude_srcs: ["c.txt"],
bazel_module: { bp2build_available: true },
}`,
- filesystem: map[string]string{
+ Filesystem: map[string]string{
"a.txt": "",
"b.txt": "",
"c.txt": "",
@@ -1202,8 +1458,8 @@
"dir/e.txt": "",
"dir/f.txt": "",
},
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
"srcs": `[
"a.txt",
"b.txt",
@@ -1214,12 +1470,12 @@
},
},
{
- description: "filegroup in subdir exclude_srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: "",
- dir: "dir",
- filesystem: map[string]string{
+ Description: "filegroup in subdir exclude_srcs",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: "",
+ Dir: "dir",
+ Filesystem: map[string]string{
"dir/Android.bp": `filegroup {
name: "fg_foo",
srcs: ["**/*.txt"],
@@ -1233,8 +1489,8 @@
"dir/subdir/e.txt": "",
"dir/subdir/f.txt": "",
},
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
"srcs": `[
"a.txt",
"//dir/subdir:e.txt",
@@ -1246,35 +1502,35 @@
}
for _, testCase := range testCases {
- t.Run(testCase.description, func(t *testing.T) {
+ t.Run(testCase.Description, func(t *testing.T) {
runBp2BuildTestCaseSimple(t, testCase)
})
}
}
func TestCommonBp2BuildModuleAttrs(t *testing.T) {
- testCases := []bp2buildTestCase{
+ testCases := []Bp2buildTestCase{
{
- description: "Required into data test",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
+ Description: "Required into data test",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
filegroup {
name: "fg_foo",
required: ["reqd"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
"data": `[":reqd"]`,
}),
},
},
{
- description: "Required via arch into data test",
- moduleTypeUnderTest: "python_library",
- moduleTypeUnderTestFactory: python.PythonLibraryFactory,
- blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") +
+ Description: "Required via arch into data test",
+ ModuleTypeUnderTest: "python_library",
+ ModuleTypeUnderTestFactory: python.PythonLibraryFactory,
+ Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") +
simpleModuleDoNotConvertBp2build("python_library", "reqdarm") + `
python_library {
name: "fg_foo",
@@ -1288,7 +1544,7 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
+ ExpectedBazelTargets: []string{
makeBazelTarget("py_library", "fg_foo", map[string]string{
"data": `select({
"//build/bazel/platforms/arch:arm": [":reqdarm"],
@@ -1301,21 +1557,21 @@
},
},
{
- description: "Required appended to data test",
- moduleTypeUnderTest: "python_library",
- moduleTypeUnderTestFactory: python.PythonLibraryFactory,
- filesystem: map[string]string{
+ Description: "Required appended to data test",
+ ModuleTypeUnderTest: "python_library",
+ ModuleTypeUnderTestFactory: python.PythonLibraryFactory,
+ Filesystem: map[string]string{
"data.bin": "",
"src.py": "",
},
- blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + `
+ Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + `
python_library {
name: "fg_foo",
data: ["data.bin"],
required: ["reqd"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
+ ExpectedBazelTargets: []string{
makeBazelTarget("py_library", "fg_foo", map[string]string{
"data": `[
"data.bin",
@@ -1327,17 +1583,17 @@
},
},
{
- description: "All props-to-attrs at once together test",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
+ Description: "All props-to-attrs at once together test",
+ ModuleTypeUnderTest: "filegroup",
+ ModuleTypeUnderTestFactory: android.FileGroupFactory,
+ Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
filegroup {
name: "fg_foo",
required: ["reqd"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
"data": `[":reqd"]`,
}),
},
@@ -1345,7 +1601,7 @@
}
for _, tc := range testCases {
- t.Run(tc.description, func(t *testing.T) {
+ t.Run(tc.Description, func(t *testing.T) {
runBp2BuildTestCaseSimple(t, tc)
})
}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index f3345a6..28d2c75 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -15,11 +15,12 @@
package bp2build
import (
- "android/soong/android"
"io/ioutil"
"os"
"strings"
"testing"
+
+ "android/soong/android"
)
func setUp() {
@@ -103,6 +104,7 @@
"one_to_many_prop": attr.bool(),
"other_embedded_prop": attr.string(),
"string_list_prop": attr.string_list(),
+ "string_literal_prop": attr.string(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
},
@@ -132,6 +134,7 @@
"one_to_many_prop": attr.bool(),
"other_embedded_prop": attr.string(),
"string_list_prop": attr.string_list(),
+ "string_literal_prop": attr.string(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
},
@@ -161,6 +164,7 @@
"one_to_many_prop": attr.bool(),
"other_embedded_prop": attr.string(),
"string_list_prop": attr.string_list(),
+ "string_literal_prop": attr.string(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
# test_prop start
@@ -189,7 +193,7 @@
content: "irrelevant",
},
}
- files := CreateBazelFiles(ruleShims, make(map[string]BazelTargets), QueryView)
+ files := CreateBazelFiles(android.NullConfig("out", "out/soong"), ruleShims, make(map[string]BazelTargets), QueryView)
var actualSoongModuleBzl BazelFile
for _, f := range files {
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 037564b..95869dd 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -31,13 +31,14 @@
type testBazelTarget struct {
typ string
name string
- attrs attrNameToString
+ attrs AttrNameToString
}
-func generateBazelTargetsForTest(targets []testBazelTarget) []string {
+func generateBazelTargetsForTest(targets []testBazelTarget, hod android.HostOrDeviceSupported) []string {
ret := make([]string, 0, len(targets))
for _, t := range targets {
- ret = append(ret, makeBazelTarget(t.typ, t.name, t.attrs))
+ attrs := t.attrs.clone()
+ ret = append(ret, makeBazelTargetHostOrDevice(t.typ, t.name, attrs, hod))
}
return ret
}
@@ -65,43 +66,34 @@
runCcHostBinaryTestCase(t, tc)
}
-func runCcBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) {
+func runCcBinaryTestCase(t *testing.T, testCase ccBinaryBp2buildTestCase) {
t.Helper()
moduleTypeUnderTest := "cc_binary"
- testCase := bp2buildTestCase{
- expectedBazelTargets: generateBazelTargetsForTest(tc.targets),
- moduleTypeUnderTest: moduleTypeUnderTest,
- moduleTypeUnderTestFactory: cc.BinaryFactory,
- description: fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description),
- blueprint: binaryReplacer.Replace(tc.blueprint),
- }
- t.Run(testCase.description, func(t *testing.T) {
+
+ description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
+ t.Run(description, func(t *testing.T) {
t.Helper()
- runBp2BuildTestCase(t, registerCcBinaryModuleTypes, testCase)
+ RunBp2BuildTestCase(t, registerCcBinaryModuleTypes, Bp2buildTestCase{
+ ExpectedBazelTargets: generateBazelTargetsForTest(testCase.targets, android.DeviceSupported),
+ ModuleTypeUnderTest: moduleTypeUnderTest,
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Description: description,
+ Blueprint: binaryReplacer.Replace(testCase.blueprint),
+ })
})
}
-func runCcHostBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) {
+func runCcHostBinaryTestCase(t *testing.T, testCase ccBinaryBp2buildTestCase) {
t.Helper()
- testCase := tc
- for i, tar := range testCase.targets {
- switch tar.typ {
- case "cc_binary", "proto_library", "cc_lite_proto_library":
- tar.attrs["target_compatible_with"] = `select({
- "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
- "//conditions:default": [],
- })`
- }
- testCase.targets[i] = tar
- }
moduleTypeUnderTest := "cc_binary_host"
- t.Run(testCase.description, func(t *testing.T) {
- runBp2BuildTestCase(t, registerCcBinaryModuleTypes, bp2buildTestCase{
- expectedBazelTargets: generateBazelTargetsForTest(testCase.targets),
- moduleTypeUnderTest: moduleTypeUnderTest,
- moduleTypeUnderTestFactory: cc.BinaryHostFactory,
- description: fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description),
- blueprint: hostBinaryReplacer.Replace(testCase.blueprint),
+ description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
+ t.Run(description, func(t *testing.T) {
+ RunBp2BuildTestCase(t, registerCcBinaryModuleTypes, Bp2buildTestCase{
+ ExpectedBazelTargets: generateBazelTargetsForTest(testCase.targets, android.HostSupported),
+ ModuleTypeUnderTest: moduleTypeUnderTest,
+ ModuleTypeUnderTestFactory: cc.BinaryHostFactory,
+ Description: description,
+ Blueprint: hostBinaryReplacer.Replace(testCase.blueprint),
})
})
}
@@ -134,7 +126,7 @@
}
`,
targets: []testBazelTarget{
- {"cc_binary", "foo", attrNameToString{
+ {"cc_binary", "foo", AttrNameToString{
"absolute_includes": `["absolute_dir"]`,
"asflags": `["-Dasflag"]`,
"conlyflags": `["-Dconlyflag"]`,
@@ -174,7 +166,7 @@
}
`,
targets: []testBazelTarget{
- {"cc_binary", "foo", attrNameToString{
+ {"cc_binary", "foo", AttrNameToString{
"features": `["-static_flag"]`,
"linkopts": `["-shared"]`,
},
@@ -194,7 +186,7 @@
}
`,
targets: []testBazelTarget{
- {"cc_binary", "foo", attrNameToString{
+ {"cc_binary", "foo", AttrNameToString{
"linkshared": `False`,
},
},
@@ -213,7 +205,7 @@
}
`,
targets: []testBazelTarget{
- {"cc_binary", "foo", attrNameToString{
+ {"cc_binary", "foo", AttrNameToString{
"additional_linker_inputs": `["vs"]`,
"linkopts": `["-Wl,--version-script,$(location vs)"]`,
},
@@ -238,7 +230,7 @@
}
` + simpleModuleDoNotConvertBp2build("filegroup", "fg_foo"),
targets: []testBazelTarget{
- {"cc_binary", "foo", attrNameToString{
+ {"cc_binary", "foo", AttrNameToString{
"srcs": `[
"cpponly.cpp",
":fg_foo_cpp_srcs",
@@ -293,7 +285,7 @@
simpleModuleDoNotConvertBp2build("cc_library", "shared_dep") +
simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep"),
targets: []testBazelTarget{
- {"cc_binary", "foo", attrNameToString{
+ {"cc_binary", "foo", AttrNameToString{
"deps": `[
":implementation_static_dep",
":static_dep",
@@ -322,21 +314,21 @@
baseTestCases := []struct {
description string
soongProperty string
- bazelAttr attrNameToString
+ bazelAttr AttrNameToString
}{
{
description: "nocrt: true",
soongProperty: `nocrt: true,`,
- bazelAttr: attrNameToString{"link_crt": `False`},
+ bazelAttr: AttrNameToString{"link_crt": `False`},
},
{
description: "nocrt: false",
soongProperty: `nocrt: false,`,
- bazelAttr: attrNameToString{},
+ bazelAttr: AttrNameToString{},
},
{
description: "nocrt: not set",
- bazelAttr: attrNameToString{},
+ bazelAttr: AttrNameToString{},
},
}
@@ -365,21 +357,21 @@
baseTestCases := []struct {
description string
soongProperty string
- bazelAttr attrNameToString
+ bazelAttr AttrNameToString
}{
{
description: "no_libcrt: true",
soongProperty: `no_libcrt: true,`,
- bazelAttr: attrNameToString{"use_libcrt": `False`},
+ bazelAttr: AttrNameToString{"use_libcrt": `False`},
},
{
description: "no_libcrt: false",
soongProperty: `no_libcrt: false,`,
- bazelAttr: attrNameToString{"use_libcrt": `True`},
+ bazelAttr: AttrNameToString{"use_libcrt": `True`},
},
{
description: "no_libcrt: not set",
- bazelAttr: attrNameToString{},
+ bazelAttr: AttrNameToString{},
},
}
@@ -408,35 +400,35 @@
baseTestCases := []struct {
description string
soongProperty string
- bazelAttr attrNameToString
+ bazelAttr AttrNameToString
}{
{
description: "pack_relocation: true",
soongProperty: `pack_relocations: true,`,
- bazelAttr: attrNameToString{},
+ bazelAttr: AttrNameToString{},
},
{
description: "pack_relocations: false",
soongProperty: `pack_relocations: false,`,
- bazelAttr: attrNameToString{"features": `["disable_pack_relocations"]`},
+ bazelAttr: AttrNameToString{"features": `["disable_pack_relocations"]`},
},
{
description: "pack_relocations: not set",
- bazelAttr: attrNameToString{},
+ bazelAttr: AttrNameToString{},
},
{
description: "pack_relocation: true",
soongProperty: `allow_undefined_symbols: true,`,
- bazelAttr: attrNameToString{"features": `["-no_undefined_symbols"]`},
+ bazelAttr: AttrNameToString{"features": `["-no_undefined_symbols"]`},
},
{
description: "allow_undefined_symbols: false",
soongProperty: `allow_undefined_symbols: false,`,
- bazelAttr: attrNameToString{},
+ bazelAttr: AttrNameToString{},
},
{
description: "allow_undefined_symbols: not set",
- bazelAttr: attrNameToString{},
+ bazelAttr: AttrNameToString{},
},
}
@@ -470,11 +462,11 @@
include_build_directory: false,
}`,
targets: []testBazelTarget{
- {"proto_library", "foo_proto", attrNameToString{
+ {"proto_library", "foo_proto", AttrNameToString{
"srcs": `["foo.proto"]`,
- }}, {"cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ }}, {"cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
"deps": `[":foo_proto"]`,
- }}, {"cc_binary", "foo", attrNameToString{
+ }}, {"cc_binary", "foo", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":foo_cc_proto_lite"]`,
}},
@@ -493,11 +485,11 @@
include_build_directory: false,
}`,
targets: []testBazelTarget{
- {"proto_library", "foo_proto", attrNameToString{
+ {"proto_library", "foo_proto", AttrNameToString{
"srcs": `["foo.proto"]`,
- }}, {"cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ }}, {"cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
"deps": `[":foo_proto"]`,
- }}, {"cc_binary", "foo", attrNameToString{
+ }}, {"cc_binary", "foo", AttrNameToString{
"deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":foo_cc_proto_lite"]`,
"linkshared": `False`,
@@ -505,3 +497,49 @@
},
})
}
+
+func TestCcBinaryConvertLex(t *testing.T) {
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
+ description: `.l and .ll sources converted to .c and .cc`,
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
+ lex: { flags: ["--foo_opt", "--bar_opt"] },
+ include_build_directory: false,
+}
+`,
+ targets: []testBazelTarget{
+ {"genlex", "foo_genlex_l", AttrNameToString{
+ "srcs": `[
+ "foo1.l",
+ "foo2.l",
+ ]`,
+ "lexopts": `[
+ "--foo_opt",
+ "--bar_opt",
+ ]`,
+ }},
+ {"genlex", "foo_genlex_ll", AttrNameToString{
+ "srcs": `[
+ "bar1.ll",
+ "bar2.ll",
+ ]`,
+ "lexopts": `[
+ "--foo_opt",
+ "--bar_opt",
+ ]`,
+ }},
+ {"cc_binary", "foo", AttrNameToString{
+ "srcs": `[
+ "bar.cc",
+ ":foo_genlex_ll",
+ ]`,
+ "srcs_c": `[
+ "foo.c",
+ ":foo_genlex_l",
+ ]`,
+ }},
+ },
+ })
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index ab92981..6c56d41 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -43,9 +43,9 @@
soongCcProtoPreamble = soongCcLibraryPreamble + soongCcProtoLibraries
)
-func runCcLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, registerCcLibraryModuleTypes, tc)
+ RunBp2BuildTestCase(t, registerCcLibraryModuleTypes, tc)
}
func registerCcLibraryModuleTypes(ctx android.RegistrationContext) {
@@ -57,11 +57,11 @@
}
func TestCcLibrarySimple(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - simple example",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library - simple example",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"android.cpp": "",
"bionic.cpp": "",
"darwin.cpp": "",
@@ -81,7 +81,7 @@
"x86_64.cpp": "",
"foo-dir/a.h": "",
},
- blueprint: soongCcLibraryPreamble +
+ Blueprint: soongCcLibraryPreamble +
simpleModuleDoNotConvertBp2build("cc_library_headers", "some-headers") + `
cc_library {
name: "foo-lib",
@@ -120,7 +120,7 @@
use_version_lib: true,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"copts": `["-Wall"]`,
"export_includes": `["foo-dir"]`,
"implementation_deps": `[":some-headers"]`,
@@ -151,18 +151,18 @@
}
func TestCcLibraryTrimmedLdAndroid(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - trimmed example of //bionic/linker:ld-android",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library - trimmed example of //bionic/linker:ld-android",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"ld-android.cpp": "",
"linked_list.h": "",
"linker.h": "",
"linker_block_allocator.h": "",
"linker_cfi.h": "",
},
- blueprint: soongCcLibraryPreamble +
+ Blueprint: soongCcLibraryPreamble +
simpleModuleDoNotConvertBp2build("cc_library_headers", "libc_headers") + `
cc_library {
name: "fake-ld-android",
@@ -193,7 +193,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("fake-ld-android", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("fake-ld-android", AttrNameToString{
"srcs": `["ld_android.cpp"]`,
"copts": `[
"-Wall",
@@ -219,12 +219,12 @@
}
func TestCcLibraryExcludeSrcs(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- dir: "external",
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Dir: "external",
+ Filesystem: map[string]string{
"external/math/cosf.c": "",
"external/math/erf.c": "",
"external/math/erf_data.c": "",
@@ -257,8 +257,8 @@
}
`,
},
- blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: makeCcLibraryTargets("fake-libarm-optimized-routines-math", attrNameToString{
+ Blueprint: soongCcLibraryPreamble,
+ ExpectedBazelTargets: makeCcLibraryTargets("fake-libarm-optimized-routines-math", AttrNameToString{
"copts": `select({
"//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"],
"//conditions:default": [],
@@ -270,16 +270,16 @@
}
func TestCcLibrarySharedStaticProps(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library shared/static props",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library shared/static props",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"both.cpp": "",
"sharedonly.cpp": "",
"staticonly.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "a",
srcs: ["both.cpp"],
@@ -354,8 +354,8 @@
bazel_module: { bp2build_available: false },
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
"copts": `[
"bothflag",
"staticflag",
@@ -377,7 +377,7 @@
":whole_and_static_lib_for_both",
":whole_static_lib_for_static",
]`}),
- makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ makeBazelTarget("cc_library_shared", "a", AttrNameToString{
"copts": `[
"bothflag",
"sharedflag",
@@ -405,16 +405,16 @@
}
func TestCcLibraryDeps(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library shared/static props",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library shared/static props",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"both.cpp": "",
"sharedonly.cpp": "",
"staticonly.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "a",
srcs: ["both.cpp"],
@@ -462,8 +462,8 @@
simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_static") +
simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_both") +
simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_both"),
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
"copts": `[
"bothflag",
"staticflag",
@@ -495,7 +495,7 @@
":whole_static_dep_for_static",
]`,
}),
- makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ makeBazelTarget("cc_library_shared", "a", AttrNameToString{
"copts": `[
"bothflag",
"sharedflag",
@@ -532,11 +532,11 @@
}
func TestCcLibraryWholeStaticLibsAlwaysLink(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- dir: "foo/bar",
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Dir: "foo/bar",
+ Filesystem: map[string]string{
"foo/bar/Android.bp": `
cc_library {
name: "a",
@@ -558,15 +558,15 @@
cc_prebuilt_library_static { name: "whole_static_lib_for_both" }
`,
},
- blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ Blueprint: soongCcLibraryPreamble,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
"whole_archive_deps": `[
":whole_static_lib_for_both_alwayslink",
":whole_static_lib_for_static_alwayslink",
]`,
}),
- makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ makeBazelTarget("cc_library_shared", "a", AttrNameToString{
"whole_archive_deps": `[
":whole_static_lib_for_both_alwayslink",
":whole_static_lib_for_shared_alwayslink",
@@ -578,12 +578,12 @@
}
func TestCcLibrarySharedStaticPropsInArch(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library shared/static props in arch",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- dir: "foo/bar",
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library shared/static props in arch",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Dir: "foo/bar",
+ Filesystem: map[string]string{
"foo/bar/arm.cpp": "",
"foo/bar/x86.cpp": "",
"foo/bar/sharedonly.cpp": "",
@@ -652,9 +652,9 @@
cc_library_static { name: "android_dep_for_shared" }
`,
},
- blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ Blueprint: soongCcLibraryPreamble,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
"copts": `[
"bothflag",
"staticflag",
@@ -678,7 +678,7 @@
"//conditions:default": [],
})`,
}),
- makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ makeBazelTarget("cc_library_shared", "a", AttrNameToString{
"copts": `[
"bothflag",
"sharedflag",
@@ -728,12 +728,12 @@
}
func TestCcLibrarySharedStaticPropsWithMixedSources(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library shared/static props with c/cpp/s mixed sources",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- dir: "foo/bar",
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library shared/static props with c/cpp/s mixed sources",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Dir: "foo/bar",
+ Filesystem: map[string]string{
"foo/bar/both_source.cpp": "",
"foo/bar/both_source.cc": "",
"foo/bar/both_source.c": "",
@@ -805,9 +805,9 @@
}
`,
},
- blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ Blueprint: soongCcLibraryPreamble,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
"local_includes": `["."]`,
"srcs": `[
"both_source.cpp",
@@ -832,7 +832,7 @@
":static_filegroup_c_srcs",
]`,
}),
- makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ makeBazelTarget("cc_library_shared", "a", AttrNameToString{
"local_includes": `["."]`,
"srcs": `[
"both_source.cpp",
@@ -860,12 +860,12 @@
}
func TestCcLibraryNonConfiguredVersionScript(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library non-configured version script",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- dir: "foo/bar",
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library non-configured version script",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Dir: "foo/bar",
+ Filesystem: map[string]string{
"foo/bar/Android.bp": `
cc_library {
name: "a",
@@ -876,8 +876,8 @@
}
`,
},
- blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ Blueprint: soongCcLibraryPreamble,
+ ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
"additional_linker_inputs": `["v.map"]`,
"linkopts": `["-Wl,--version-script,$(location v.map)"]`,
"srcs": `["a.cpp"]`,
@@ -887,12 +887,12 @@
}
func TestCcLibraryConfiguredVersionScript(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library configured version script",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- dir: "foo/bar",
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library configured version script",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Dir: "foo/bar",
+ Filesystem: map[string]string{
"foo/bar/Android.bp": `
cc_library {
name: "a",
@@ -911,8 +911,8 @@
}
`,
},
- blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ Blueprint: soongCcLibraryPreamble,
+ ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
"additional_linker_inputs": `select({
"//build/bazel/platforms/arch:arm": ["arm.map"],
"//build/bazel/platforms/arch:arm64": ["arm64.map"],
@@ -930,11 +930,11 @@
}
func TestCcLibrarySharedLibs(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library shared_libs",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library shared_libs",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "mylib",
bazel_module: { bp2build_available: false },
@@ -946,7 +946,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
"implementation_dynamic_deps": `[":mylib"]`,
}),
},
@@ -955,15 +955,16 @@
func TestCcLibraryFeatures(t *testing.T) {
expected_targets := []string{}
- expected_targets = append(expected_targets, makeCcLibraryTargets("a", attrNameToString{
+ expected_targets = append(expected_targets, makeCcLibraryTargets("a", AttrNameToString{
"features": `[
"disable_pack_relocations",
"-no_undefined_symbols",
+ "-coverage",
]`,
"srcs": `["a.cpp"]`,
})...)
- expected_targets = append(expected_targets, makeCcLibraryTargets("b", attrNameToString{
- "features": `select({
+ expected_targets = append(expected_targets, makeCcLibraryTargets("b", AttrNameToString{
+ "features": `["-coverage"] + select({
"//build/bazel/platforms/arch:x86_64": [
"disable_pack_relocations",
"-no_undefined_symbols",
@@ -972,7 +973,7 @@
})`,
"srcs": `["b.cpp"]`,
})...)
- expected_targets = append(expected_targets, makeCcLibraryTargets("c", attrNameToString{
+ expected_targets = append(expected_targets, makeCcLibraryTargets("c", AttrNameToString{
"features": `select({
"//build/bazel/platforms/os:darwin": [
"disable_pack_relocations",
@@ -983,17 +984,18 @@
"srcs": `["c.cpp"]`,
})...)
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library pack_relocations test",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library pack_relocations test",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "a",
srcs: ["a.cpp"],
pack_relocations: false,
allow_undefined_symbols: true,
include_build_directory: false,
+ native_coverage: false,
}
cc_library {
@@ -1006,6 +1008,7 @@
},
},
include_build_directory: false,
+ native_coverage: false,
}
cc_library {
@@ -1019,23 +1022,23 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: expected_targets,
+ ExpectedBazelTargets: expected_targets,
})
}
func TestCcLibrarySpacesInCopts(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library spaces in copts",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library spaces in copts",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "a",
cflags: ["-include header.h",],
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
"copts": `[
"-include",
"header.h",
@@ -1046,11 +1049,11 @@
}
func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library cppflags usage",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library cppflags usage",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `cc_library {
name: "a",
srcs: ["a.cpp"],
cflags: ["-Wall"],
@@ -1071,7 +1074,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
"copts": `["-Wall"]`,
"cppflags": `[
"-fsigned-char",
@@ -1090,11 +1093,11 @@
}
func TestCcLibraryExcludeLibs(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{},
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library {
name: "foo_static",
srcs: ["common.c"],
@@ -1168,7 +1171,7 @@
bazel_module: { bp2build_available: false },
}
`,
- expectedBazelTargets: makeCcLibraryTargets("foo_static", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo_static", AttrNameToString{
"implementation_deps": `select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"],
@@ -1197,14 +1200,14 @@
}
func TestCCLibraryNoCrtTrue(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - nocrt: true emits attribute",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library - nocrt: true emits attribute",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -1212,7 +1215,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"link_crt": `False`,
"srcs": `["impl.cpp"]`,
}),
@@ -1221,14 +1224,14 @@
}
func TestCCLibraryNoCrtFalse(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - nocrt: false - does not emit attribute",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library - nocrt: false - does not emit attribute",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -1236,21 +1239,21 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"srcs": `["impl.cpp"]`,
}),
})
}
func TestCCLibraryNoCrtArchVariant(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - nocrt in select",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library - nocrt in select",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -1265,18 +1268,18 @@
include_build_directory: false,
}
`,
- expectedErr: fmt.Errorf("module \"foo-lib\": nocrt is not supported for arch variants"),
+ ExpectedErr: fmt.Errorf("module \"foo-lib\": nocrt is not supported for arch variants"),
})
}
func TestCCLibraryNoLibCrtTrue(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -1284,14 +1287,14 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"srcs": `["impl.cpp"]`,
"use_libcrt": `False`,
}),
})
}
-func makeCcLibraryTargets(name string, attrs attrNameToString) []string {
+func makeCcLibraryTargets(name string, attrs AttrNameToString) []string {
STATIC_ONLY_ATTRS := map[string]bool{}
SHARED_ONLY_ATTRS := map[string]bool{
"link_crt": true,
@@ -1302,8 +1305,8 @@
"stubs_versions": true,
"inject_bssl_hash": true,
}
- sharedAttrs := attrNameToString{}
- staticAttrs := attrNameToString{}
+ sharedAttrs := AttrNameToString{}
+ staticAttrs := AttrNameToString{}
for key, val := range attrs {
if _, staticOnly := STATIC_ONLY_ATTRS[key]; !staticOnly {
sharedAttrs[key] = val
@@ -1319,13 +1322,13 @@
}
func TestCCLibraryNoLibCrtFalse(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -1333,7 +1336,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"srcs": `["impl.cpp"]`,
"use_libcrt": `True`,
}),
@@ -1341,13 +1344,13 @@
}
func TestCCLibraryNoLibCrtArchVariant(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -1362,7 +1365,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"srcs": `["impl.cpp"]`,
"use_libcrt": `select({
"//build/bazel/platforms/arch:arm": False,
@@ -1374,13 +1377,13 @@
}
func TestCCLibraryNoLibCrtArchAndTargetVariant(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -1400,7 +1403,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"srcs": `["impl.cpp"]`,
"use_libcrt": `select({
"//build/bazel/platforms/os_arch:android_arm": False,
@@ -1417,13 +1420,13 @@
}
func TestCCLibraryNoLibCrtArchAndTargetVariantConflict(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -1444,7 +1447,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"srcs": `["impl.cpp"]`,
"use_libcrt": `select({
"//build/bazel/platforms/os_arch:android_arm": False,
@@ -1463,38 +1466,38 @@
func TestCcLibraryStrip(t *testing.T) {
expectedTargets := []string{}
- expectedTargets = append(expectedTargets, makeCcLibraryTargets("all", attrNameToString{
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("all", AttrNameToString{
"strip": `{
"all": True,
}`,
})...)
- expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols", attrNameToString{
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols", AttrNameToString{
"strip": `{
"keep_symbols": True,
}`,
})...)
- expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_and_debug_frame", attrNameToString{
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_and_debug_frame", AttrNameToString{
"strip": `{
"keep_symbols_and_debug_frame": True,
}`,
})...)
- expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_list", attrNameToString{
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_list", AttrNameToString{
"strip": `{
"keep_symbols_list": ["symbol"],
}`,
})...)
- expectedTargets = append(expectedTargets, makeCcLibraryTargets("none", attrNameToString{
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("none", AttrNameToString{
"strip": `{
"none": True,
}`,
})...)
- expectedTargets = append(expectedTargets, makeCcLibraryTargets("nothing", attrNameToString{})...)
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("nothing", AttrNameToString{})...)
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library strip args",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library strip args",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "nothing",
include_build_directory: false,
@@ -1535,16 +1538,16 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: expectedTargets,
+ ExpectedBazelTargets: expectedTargets,
})
}
func TestCcLibraryStripWithArch(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library strip args",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library strip args",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "multi-arch",
target: {
@@ -1569,7 +1572,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("multi-arch", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("multi-arch", AttrNameToString{
"strip": `{
"keep_symbols": select({
"//build/bazel/platforms/arch:arm64": True,
@@ -1593,18 +1596,18 @@
}
func TestCcLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty at root",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library system_shared_libs empty at root",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "root_empty",
system_shared_libs: [],
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("root_empty", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("root_empty", AttrNameToString{
"system_dynamic_deps": `[]`,
}),
},
@@ -1612,11 +1615,11 @@
}
func TestCcLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty for static variant",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library system_shared_libs empty for static variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "static_empty",
static: {
@@ -1625,21 +1628,21 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "static_empty_bp2build_cc_library_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "static_empty_bp2build_cc_library_static", AttrNameToString{
"system_dynamic_deps": "[]",
}),
- makeBazelTarget("cc_library_shared", "static_empty", attrNameToString{}),
+ makeBazelTarget("cc_library_shared", "static_empty", AttrNameToString{}),
},
})
}
func TestCcLibrary_SystemSharedLibsSharedEmpty(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty for shared variant",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library system_shared_libs empty for shared variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "shared_empty",
shared: {
@@ -1648,9 +1651,9 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", attrNameToString{}),
- makeBazelTarget("cc_library_shared", "shared_empty", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", AttrNameToString{}),
+ makeBazelTarget("cc_library_shared", "shared_empty", AttrNameToString{
"system_dynamic_deps": "[]",
}),
},
@@ -1658,11 +1661,11 @@
}
func TestCcLibrary_SystemSharedLibsSharedBionicEmpty(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty for shared, bionic variant",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library system_shared_libs empty for shared, bionic variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "shared_empty",
target: {
@@ -1675,9 +1678,9 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", attrNameToString{}),
- makeBazelTarget("cc_library_shared", "shared_empty", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", AttrNameToString{}),
+ makeBazelTarget("cc_library_shared", "shared_empty", AttrNameToString{
"system_dynamic_deps": "[]",
}),
},
@@ -1689,11 +1692,11 @@
// The correct behavior would be if bp2build wrote `system_dynamic_deps = []`
// only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
// b/195791252 tracks the fix.
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty for linux_bionic variant",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library system_shared_libs empty for linux_bionic variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "target_linux_bionic_empty",
target: {
@@ -1704,7 +1707,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("target_linux_bionic_empty", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("target_linux_bionic_empty", AttrNameToString{
"system_dynamic_deps": `[]`,
}),
},
@@ -1712,11 +1715,11 @@
}
func TestCcLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty for bionic variant",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library system_shared_libs empty for bionic variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "target_bionic_empty",
target: {
@@ -1727,7 +1730,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("target_bionic_empty", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("target_bionic_empty", AttrNameToString{
"system_dynamic_deps": `[]`,
}),
},
@@ -1735,11 +1738,11 @@
}
func TestCcLibrary_SystemSharedLibsSharedAndRoot(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs set for shared and root",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library system_shared_libs set for shared and root",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "libc",
bazel_module: { bp2build_available: false },
@@ -1758,11 +1761,11 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
"system_dynamic_deps": `[":libc"]`,
}),
- makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"system_dynamic_deps": `[
":libc",
":libm",
@@ -1773,12 +1776,12 @@
}
func TestCcLibraryOsSelects(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - selects for all os targets",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{},
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library - selects for all os targets",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "foo-lib",
srcs: ["base.cpp"],
@@ -1808,7 +1811,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
"srcs": `["base.cpp"] + select({
"//build/bazel/platforms/os:android": [
"linux.cpp",
@@ -1837,12 +1840,12 @@
}
func TestLibcryptoHashInjection(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - libcrypto hash injection",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- filesystem: map[string]string{},
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library - libcrypto hash injection",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryPreamble + `
cc_library {
name: "libcrypto",
target: {
@@ -1853,7 +1856,7 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: makeCcLibraryTargets("libcrypto", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("libcrypto", AttrNameToString{
"inject_bssl_hash": `select({
"//build/bazel/platforms/os:android": True,
"//conditions:default": None,
@@ -1879,76 +1882,78 @@
// not set, only emit if gnu_extensions is disabled. the default (gnu+17
// is set in the toolchain.)
{cpp_std: "", gnu_extensions: "", bazel_cpp_std: ""},
- {cpp_std: "", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c99"},
+ {cpp_std: "", gnu_extensions: "false", bazel_cpp_std: "cpp_std_default_no_gnu", bazel_c_std: "c_std_default_no_gnu"},
{cpp_std: "", gnu_extensions: "true", bazel_cpp_std: ""},
// experimental defaults to gnu++2a
- {cpp_std: "experimental", gnu_extensions: "", bazel_cpp_std: "gnu++2a"},
- {cpp_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++2a", bazel_c_std: "c99"},
- {cpp_std: "experimental", gnu_extensions: "true", bazel_cpp_std: "gnu++2a"},
+ {cpp_std: "experimental", gnu_extensions: "", bazel_cpp_std: "cpp_std_experimental"},
+ {cpp_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "cpp_std_experimental_no_gnu", bazel_c_std: "c_std_default_no_gnu"},
+ {cpp_std: "experimental", gnu_extensions: "true", bazel_cpp_std: "cpp_std_experimental"},
// Explicitly setting a c++ std does not use replace gnu++ std even if
// gnu_extensions is true.
// "c++11",
{cpp_std: "c++11", gnu_extensions: "", bazel_cpp_std: "c++11"},
- {cpp_std: "c++11", gnu_extensions: "false", bazel_cpp_std: "c++11", bazel_c_std: "c99"},
+ {cpp_std: "c++11", gnu_extensions: "false", bazel_cpp_std: "c++11", bazel_c_std: "c_std_default_no_gnu"},
{cpp_std: "c++11", gnu_extensions: "true", bazel_cpp_std: "c++11"},
// "c++17",
{cpp_std: "c++17", gnu_extensions: "", bazel_cpp_std: "c++17"},
- {cpp_std: "c++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c99"},
+ {cpp_std: "c++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c_std_default_no_gnu"},
{cpp_std: "c++17", gnu_extensions: "true", bazel_cpp_std: "c++17"},
// "c++2a",
{cpp_std: "c++2a", gnu_extensions: "", bazel_cpp_std: "c++2a"},
- {cpp_std: "c++2a", gnu_extensions: "false", bazel_cpp_std: "c++2a", bazel_c_std: "c99"},
+ {cpp_std: "c++2a", gnu_extensions: "false", bazel_cpp_std: "c++2a", bazel_c_std: "c_std_default_no_gnu"},
{cpp_std: "c++2a", gnu_extensions: "true", bazel_cpp_std: "c++2a"},
// "c++98",
{cpp_std: "c++98", gnu_extensions: "", bazel_cpp_std: "c++98"},
- {cpp_std: "c++98", gnu_extensions: "false", bazel_cpp_std: "c++98", bazel_c_std: "c99"},
+ {cpp_std: "c++98", gnu_extensions: "false", bazel_cpp_std: "c++98", bazel_c_std: "c_std_default_no_gnu"},
{cpp_std: "c++98", gnu_extensions: "true", bazel_cpp_std: "c++98"},
// gnu++ is replaced with c++ if gnu_extensions is explicitly false.
// "gnu++11",
{cpp_std: "gnu++11", gnu_extensions: "", bazel_cpp_std: "gnu++11"},
- {cpp_std: "gnu++11", gnu_extensions: "false", bazel_cpp_std: "c++11", bazel_c_std: "c99"},
+ {cpp_std: "gnu++11", gnu_extensions: "false", bazel_cpp_std: "c++11", bazel_c_std: "c_std_default_no_gnu"},
{cpp_std: "gnu++11", gnu_extensions: "true", bazel_cpp_std: "gnu++11"},
// "gnu++17",
{cpp_std: "gnu++17", gnu_extensions: "", bazel_cpp_std: "gnu++17"},
- {cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c99"},
+ {cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c_std_default_no_gnu"},
{cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17"},
// some c_std test cases
- {c_std: "experimental", gnu_extensions: "", bazel_c_std: "gnu17"},
- {c_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c17"},
- {c_std: "experimental", gnu_extensions: "true", bazel_c_std: "gnu17"},
+ {c_std: "experimental", gnu_extensions: "", bazel_c_std: "c_std_experimental"},
+ {c_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "cpp_std_default_no_gnu", bazel_c_std: "c_std_experimental_no_gnu"},
+ {c_std: "experimental", gnu_extensions: "true", bazel_c_std: "c_std_experimental"},
{c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "", bazel_cpp_std: "gnu++17", bazel_c_std: "gnu11"},
{c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c11"},
{c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17", bazel_c_std: "gnu11"},
}
for i, tc := range testCases {
- name_prefix := fmt.Sprintf("a_%v", i)
- cppStdProp := ""
- if tc.cpp_std != "" {
- cppStdProp = fmt.Sprintf(" cpp_std: \"%s\",", tc.cpp_std)
- }
- cStdProp := ""
- if tc.c_std != "" {
- cStdProp = fmt.Sprintf(" c_std: \"%s\",", tc.c_std)
- }
- gnuExtensionsProp := ""
- if tc.gnu_extensions != "" {
- gnuExtensionsProp = fmt.Sprintf(" gnu_extensions: %s,", tc.gnu_extensions)
- }
- attrs := attrNameToString{}
- if tc.bazel_cpp_std != "" {
- attrs["cpp_std"] = fmt.Sprintf(`"%s"`, tc.bazel_cpp_std)
- }
- if tc.bazel_c_std != "" {
- attrs["c_std"] = fmt.Sprintf(`"%s"`, tc.bazel_c_std)
- }
+ name := fmt.Sprintf("cpp std: %q, c std: %q, gnu_extensions: %q", tc.cpp_std, tc.c_std, tc.gnu_extensions)
+ t.Run(name, func(t *testing.T) {
+ name_prefix := fmt.Sprintf("a_%v", i)
+ cppStdProp := ""
+ if tc.cpp_std != "" {
+ cppStdProp = fmt.Sprintf(" cpp_std: \"%s\",", tc.cpp_std)
+ }
+ cStdProp := ""
+ if tc.c_std != "" {
+ cStdProp = fmt.Sprintf(" c_std: \"%s\",", tc.c_std)
+ }
+ gnuExtensionsProp := ""
+ if tc.gnu_extensions != "" {
+ gnuExtensionsProp = fmt.Sprintf(" gnu_extensions: %s,", tc.gnu_extensions)
+ }
+ attrs := AttrNameToString{}
+ if tc.bazel_cpp_std != "" {
+ attrs["cpp_std"] = fmt.Sprintf(`"%s"`, tc.bazel_cpp_std)
+ }
+ if tc.bazel_c_std != "" {
+ attrs["c_std"] = fmt.Sprintf(`"%s"`, tc.bazel_c_std)
+ }
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: fmt.Sprintf(
- "cc_library with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: fmt.Sprintf(
+ "cc_library with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
cc_library {
name: "%s_full",
%s // cpp_std: *string
@@ -1957,15 +1962,15 @@
include_build_directory: false,
}
`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
- expectedBazelTargets: makeCcLibraryTargets(name_prefix+"_full", attrs),
- })
+ ExpectedBazelTargets: makeCcLibraryTargets(name_prefix+"_full", attrs),
+ })
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: fmt.Sprintf(
- "cc_library_static with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: fmt.Sprintf(
+ "cc_library_static with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
cc_library_static {
name: "%s_static",
%s // cpp_std: *string
@@ -1974,17 +1979,17 @@
include_build_directory: false,
}
`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", name_prefix+"_static", attrs),
- },
- })
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", name_prefix+"_static", attrs),
+ },
+ })
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: fmt.Sprintf(
- "cc_library_shared with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: fmt.Sprintf(
+ "cc_library_shared with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
+ ModuleTypeUnderTest: "cc_library_shared",
+ ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ Blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
cc_library_shared {
name: "%s_shared",
%s // cpp_std: *string
@@ -1993,31 +1998,32 @@
include_build_directory: false,
}
`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", name_prefix+"_shared", attrs),
- },
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", name_prefix+"_shared", attrs),
+ },
+ })
})
}
}
func TestCcLibraryProtoSimple(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
srcs: ["foo.proto"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
"srcs": `["foo.proto"]`,
- }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
"deps": `[":foo_proto"]`,
- }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
"deps": `[":libprotobuf-cpp-lite"]`,
- }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
}),
},
@@ -2025,25 +2031,25 @@
}
func TestCcLibraryProtoNoCanonicalPathFromRoot(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
srcs: ["foo.proto"],
proto: { canonical_path_from_root: false},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
"srcs": `["foo.proto"]`,
"strip_import_prefix": `""`,
- }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
"deps": `[":foo_proto"]`,
- }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
"deps": `[":libprotobuf-cpp-lite"]`,
- }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
}),
},
@@ -2051,24 +2057,24 @@
}
func TestCcLibraryProtoExplicitCanonicalPathFromRoot(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
srcs: ["foo.proto"],
proto: { canonical_path_from_root: true},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
"srcs": `["foo.proto"]`,
- }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
"deps": `[":foo_proto"]`,
- }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
"deps": `[":libprotobuf-cpp-lite"]`,
- }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
}),
},
@@ -2076,10 +2082,10 @@
}
func TestCcLibraryProtoFull(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
srcs: ["foo.proto"],
proto: {
@@ -2087,15 +2093,15 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
"srcs": `["foo.proto"]`,
- }), makeBazelTarget("cc_proto_library", "foo_cc_proto", attrNameToString{
+ }), makeBazelTarget("cc_proto_library", "foo_cc_proto", AttrNameToString{
"deps": `[":foo_proto"]`,
- }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
"implementation_whole_archive_deps": `[":foo_cc_proto"]`,
"deps": `[":libprotobuf-cpp-full"]`,
- }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-full"]`,
}),
},
@@ -2103,10 +2109,10 @@
}
func TestCcLibraryProtoLite(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
srcs: ["foo.proto"],
proto: {
@@ -2114,15 +2120,15 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
"srcs": `["foo.proto"]`,
- }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
"deps": `[":foo_proto"]`,
- }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
"deps": `[":libprotobuf-cpp-lite"]`,
- }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
}),
},
@@ -2130,10 +2136,10 @@
}
func TestCcLibraryProtoExportHeaders(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
srcs: ["foo.proto"],
proto: {
@@ -2141,15 +2147,15 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
"srcs": `["foo.proto"]`,
- }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
"deps": `[":foo_proto"]`,
- }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
"deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":foo_cc_proto_lite"]`,
- }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":foo_cc_proto_lite"]`,
}),
@@ -2158,10 +2164,10 @@
}
func TestCcLibraryProtoFilegroups(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble +
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble +
simpleModuleDoNotConvertBp2build("filegroup", "a_fg_proto") +
simpleModuleDoNotConvertBp2build("filegroup", "b_protos") +
simpleModuleDoNotConvertBp2build("filegroup", "c-proto-srcs") +
@@ -2201,66 +2207,66 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("proto_library", "a_proto", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "a_proto", AttrNameToString{
"srcs": `[":a_fg_proto"]`,
- }), makeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", AttrNameToString{
"deps": `[":a_proto"]`,
- }), makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
"deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":a_cc_proto_lite"]`,
"srcs": `[":a_fg_proto_cpp_srcs"]`,
"srcs_as": `[":a_fg_proto_as_srcs"]`,
"srcs_c": `[":a_fg_proto_c_srcs"]`,
- }), makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "a", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":a_cc_proto_lite"]`,
"srcs": `[":a_fg_proto_cpp_srcs"]`,
"srcs_as": `[":a_fg_proto_as_srcs"]`,
"srcs_c": `[":a_fg_proto_c_srcs"]`,
- }), makeBazelTarget("proto_library", "b_proto", attrNameToString{
+ }), makeBazelTarget("proto_library", "b_proto", AttrNameToString{
"srcs": `[":b_protos"]`,
- }), makeBazelTarget("cc_lite_proto_library", "b_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "b_cc_proto_lite", AttrNameToString{
"deps": `[":b_proto"]`,
- }), makeBazelTarget("cc_library_static", "b_bp2build_cc_library_static", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "b_bp2build_cc_library_static", AttrNameToString{
"deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":b_cc_proto_lite"]`,
"srcs": `[":b_protos_cpp_srcs"]`,
"srcs_as": `[":b_protos_as_srcs"]`,
"srcs_c": `[":b_protos_c_srcs"]`,
- }), makeBazelTarget("cc_library_shared", "b", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "b", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":b_cc_proto_lite"]`,
"srcs": `[":b_protos_cpp_srcs"]`,
"srcs_as": `[":b_protos_as_srcs"]`,
"srcs_c": `[":b_protos_c_srcs"]`,
- }), makeBazelTarget("proto_library", "c_proto", attrNameToString{
+ }), makeBazelTarget("proto_library", "c_proto", AttrNameToString{
"srcs": `[":c-proto-srcs"]`,
- }), makeBazelTarget("cc_lite_proto_library", "c_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "c_cc_proto_lite", AttrNameToString{
"deps": `[":c_proto"]`,
- }), makeBazelTarget("cc_library_static", "c_bp2build_cc_library_static", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "c_bp2build_cc_library_static", AttrNameToString{
"deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":c_cc_proto_lite"]`,
"srcs": `[":c-proto-srcs_cpp_srcs"]`,
"srcs_as": `[":c-proto-srcs_as_srcs"]`,
"srcs_c": `[":c-proto-srcs_c_srcs"]`,
- }), makeBazelTarget("cc_library_shared", "c", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "c", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":c_cc_proto_lite"]`,
"srcs": `[":c-proto-srcs_cpp_srcs"]`,
"srcs_as": `[":c-proto-srcs_as_srcs"]`,
"srcs_c": `[":c-proto-srcs_c_srcs"]`,
- }), makeBazelTarget("proto_library", "d_proto", attrNameToString{
+ }), makeBazelTarget("proto_library", "d_proto", AttrNameToString{
"srcs": `[":proto-srcs-d"]`,
- }), makeBazelTarget("cc_lite_proto_library", "d_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "d_cc_proto_lite", AttrNameToString{
"deps": `[":d_proto"]`,
- }), makeBazelTarget("cc_library_static", "d_bp2build_cc_library_static", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "d_bp2build_cc_library_static", AttrNameToString{
"deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":d_cc_proto_lite"]`,
"srcs": `[":proto-srcs-d_cpp_srcs"]`,
"srcs_as": `[":proto-srcs-d_as_srcs"]`,
"srcs_c": `[":proto-srcs-d_c_srcs"]`,
- }), makeBazelTarget("cc_library_shared", "d", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "d", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":d_cc_proto_lite"]`,
"srcs": `[":proto-srcs-d_cpp_srcs"]`,
@@ -2272,12 +2278,13 @@
}
func TestCcLibraryDisabledArchAndTarget(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
srcs: ["foo.cpp"],
+ host_supported: true,
target: {
darwin: {
enabled: false,
@@ -2291,7 +2298,7 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: makeCcLibraryTargets("foo", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
"srcs": `["foo.cpp"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"],
@@ -2306,13 +2313,14 @@
}
func TestCcLibraryDisabledArchAndTargetWithDefault(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
srcs: ["foo.cpp"],
enabled: false,
+ host_supported: true,
target: {
darwin: {
enabled: true,
@@ -2326,7 +2334,7 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: makeCcLibraryTargets("foo", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
"srcs": `["foo.cpp"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os_arch:darwin_arm64": [],
@@ -2338,10 +2346,10 @@
}
func TestCcLibrarySharedDisabled(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
srcs: ["foo.cpp"],
enabled: false,
@@ -2357,10 +2365,10 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ ExpectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
"srcs": `["foo.cpp"]`,
"target_compatible_with": `["@platforms//:incompatible"]`,
- }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"srcs": `["foo.cpp"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
@@ -2372,11 +2380,12 @@
}
func TestCcLibraryStaticDisabledForSomeArch(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
+ host_supported: true,
srcs: ["foo.cpp"],
shared: {
enabled: false
@@ -2396,13 +2405,13 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ ExpectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
"srcs": `["foo.cpp"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:windows": ["@platforms//:incompatible"],
"//conditions:default": [],
})`,
- }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"srcs": `["foo.cpp"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os_arch:darwin_arm64": [],
@@ -2415,12 +2424,12 @@
}
func TestCcLibraryStubs(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library stubs",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- dir: "foo/bar",
- filesystem: map[string]string{
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library stubs",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Dir: "foo/bar",
+ Filesystem: map[string]string{
"foo/bar/Android.bp": `
cc_library {
name: "a",
@@ -2430,8 +2439,8 @@
}
`,
},
- blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ Blueprint: soongCcLibraryPreamble,
+ ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
"stubs_symbol_file": `"a.map.txt"`,
"stubs_versions": `[
"28",
@@ -2444,16 +2453,64 @@
}
func TestCcLibraryEscapeLdflags(t *testing.T) {
- runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- blueprint: soongCcProtoPreamble + `cc_library {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcProtoPreamble + `cc_library {
name: "foo",
ldflags: ["-Wl,--rpath,${ORIGIN}"],
include_build_directory: false,
}`,
- expectedBazelTargets: makeCcLibraryTargets("foo", attrNameToString{
+ ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
"linkopts": `["-Wl,--rpath,$${ORIGIN}"]`,
}),
})
}
+
+func TestCcLibraryConvertLex(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
+ "foo.c": "",
+ "bar.cc": "",
+ "foo1.l": "",
+ "bar1.ll": "",
+ "foo2.l": "",
+ "bar2.ll": "",
+ },
+ Blueprint: `cc_library {
+ name: "foo_lib",
+ srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
+ lex: { flags: ["--foo_flags"] },
+ include_build_directory: false,
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: append([]string{
+ makeBazelTarget("genlex", "foo_lib_genlex_l", AttrNameToString{
+ "srcs": `[
+ "foo1.l",
+ "foo2.l",
+ ]`,
+ "lexopts": `["--foo_flags"]`,
+ }),
+ makeBazelTarget("genlex", "foo_lib_genlex_ll", AttrNameToString{
+ "srcs": `[
+ "bar1.ll",
+ "bar2.ll",
+ ]`,
+ "lexopts": `["--foo_flags"]`,
+ }),
+ },
+ makeCcLibraryTargets("foo_lib", AttrNameToString{
+ "srcs": `[
+ "bar.cc",
+ ":foo_lib_genlex_ll",
+ ]`,
+ "srcs_c": `[
+ "foo.c",
+ ":foo_lib_genlex_l",
+ ]`,
+ })...),
+ })
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index e5bb120..bb59c63 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -59,17 +59,17 @@
cc.RegisterCCBuildComponents(ctx)
}
-func runCcLibraryHeadersTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcLibraryHeadersTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, registerCcLibraryHeadersModuleTypes, tc)
+ RunBp2BuildTestCase(t, registerCcLibraryHeadersModuleTypes, tc)
}
func TestCcLibraryHeadersSimple(t *testing.T) {
- runCcLibraryHeadersTestCase(t, bp2buildTestCase{
- description: "cc_library_headers test",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- filesystem: map[string]string{
+ runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_headers test",
+ ModuleTypeUnderTest: "cc_library_headers",
+ ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ Filesystem: map[string]string{
"lib-1/lib1a.h": "",
"lib-1/lib1b.h": "",
"lib-2/lib2a.h": "",
@@ -82,19 +82,7 @@
"arch_x86_exported_include_dir/b.h": "",
"arch_x86_64_exported_include_dir/c.h": "",
},
- blueprint: soongCcLibraryHeadersPreamble + `
-cc_library_headers {
- name: "lib-1",
- export_include_dirs: ["lib-1"],
- bazel_module: { bp2build_available: false },
-}
-
-cc_library_headers {
- name: "lib-2",
- export_include_dirs: ["lib-2"],
- bazel_module: { bp2build_available: false },
-}
-
+ Blueprint: soongCcLibraryHeadersPreamble + `
cc_library_headers {
name: "foo_headers",
export_include_dirs: ["dir-1", "dir-2"],
@@ -117,8 +105,8 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
"export_includes": `[
"dir-1",
"dir-2",
@@ -128,24 +116,20 @@
"//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"],
"//conditions:default": [],
})`,
- "implementation_deps": `[
- ":lib-1",
- ":lib-2",
- ]`,
- "sdk_version": `"current"`,
- "min_sdk_version": `"29"`,
+ "sdk_version": `"current"`,
+ "min_sdk_version": `"29"`,
}),
},
})
}
func TestCcLibraryHeadersOsSpecificHeader(t *testing.T) {
- runCcLibraryHeadersTestCase(t, bp2buildTestCase{
- description: "cc_library_headers test with os-specific header_libs props",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- filesystem: map[string]string{},
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_headers test with os-specific header_libs props",
+ ModuleTypeUnderTest: "cc_library_headers",
+ ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryPreamble + `
cc_library_headers {
name: "android-lib",
bazel_module: { bp2build_available: false },
@@ -173,18 +157,34 @@
cc_library_headers {
name: "foo_headers",
header_libs: ["base-lib"],
+ export_header_lib_headers: ["base-lib"],
target: {
- android: { header_libs: ["android-lib"] },
- darwin: { header_libs: ["darwin-lib"] },
- linux_bionic: { header_libs: ["linux_bionic-lib"] },
- linux_glibc: { header_libs: ["linux-lib"] },
- windows: { header_libs: ["windows-lib"] },
+ android: {
+ header_libs: ["android-lib"],
+ export_header_lib_headers: ["android-lib"],
+ },
+ darwin: {
+ header_libs: ["darwin-lib"],
+ export_header_lib_headers: ["darwin-lib"],
+ },
+ linux_bionic: {
+ header_libs: ["linux_bionic-lib"],
+ export_header_lib_headers: ["linux_bionic-lib"],
+ },
+ linux_glibc: {
+ header_libs: ["linux-lib"],
+ export_header_lib_headers: ["linux-lib"],
+ },
+ windows: {
+ header_libs: ["windows-lib"],
+ export_header_lib_headers: ["windows-lib"],
+ },
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
- "implementation_deps": `[":base-lib"] + select({
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
+ "deps": `[":base-lib"] + select({
"//build/bazel/platforms/os:android": [":android-lib"],
"//build/bazel/platforms/os:darwin": [":darwin-lib"],
"//build/bazel/platforms/os:linux": [":linux-lib"],
@@ -198,12 +198,12 @@
}
func TestCcLibraryHeadersOsSpecficHeaderLibsExportHeaderLibHeaders(t *testing.T) {
- runCcLibraryHeadersTestCase(t, bp2buildTestCase{
- description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- filesystem: map[string]string{},
- blueprint: soongCcLibraryPreamble + `
+ runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props",
+ ModuleTypeUnderTest: "cc_library_headers",
+ ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryPreamble + `
cc_library_headers {
name: "android-lib",
bazel_module: { bp2build_available: false },
@@ -222,28 +222,24 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
"deps": `select({
"//build/bazel/platforms/os:android": [":exported-lib"],
"//conditions:default": [],
})`,
- "implementation_deps": `select({
- "//build/bazel/platforms/os:android": [":android-lib"],
- "//conditions:default": [],
- })`,
}),
},
})
}
func TestCcLibraryHeadersArchAndTargetExportSystemIncludes(t *testing.T) {
- runCcLibraryHeadersTestCase(t, bp2buildTestCase{
- description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- filesystem: map[string]string{},
- blueprint: soongCcLibraryPreamble + `cc_library_headers {
+ runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props",
+ ModuleTypeUnderTest: "cc_library_headers",
+ ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryPreamble + `cc_library_headers {
name: "foo_headers",
export_system_include_dirs: [
"shared_include_dir",
@@ -279,8 +275,8 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
"export_system_includes": `["shared_include_dir"] + select({
"//build/bazel/platforms/arch:arm": ["arm_include_dir"],
"//build/bazel/platforms/arch:x86_64": ["x86_64_include_dir"],
@@ -297,11 +293,11 @@
}
func TestCcLibraryHeadersNoCrtIgnored(t *testing.T) {
- runCcLibraryHeadersTestCase(t, bp2buildTestCase{
- description: "cc_library_headers test",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- filesystem: map[string]string{
+ runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_headers test",
+ ModuleTypeUnderTest: "cc_library_headers",
+ ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ Filesystem: map[string]string{
"lib-1/lib1a.h": "",
"lib-1/lib1b.h": "",
"lib-2/lib2a.h": "",
@@ -314,17 +310,83 @@
"arch_x86_exported_include_dir/b.h": "",
"arch_x86_64_exported_include_dir/c.h": "",
},
- blueprint: soongCcLibraryHeadersPreamble + `
+ Blueprint: soongCcLibraryHeadersPreamble + `
cc_library_headers {
name: "lib-1",
export_include_dirs: ["lib-1"],
no_libcrt: true,
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_headers", "lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "lib-1", AttrNameToString{
"export_includes": `["lib-1"]`,
}),
},
})
}
+
+func TestCcLibraryHeadersExportedStaticLibHeadersReexported(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_headers exported_static_lib_headers is reexported",
+ ModuleTypeUnderTest: "cc_library_headers",
+ ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryHeadersPreamble + `
+cc_library_headers {
+ name: "foo_headers",
+ export_static_lib_headers: ["foo_export"],
+ static_libs: ["foo_export", "foo_no_reexport"],
+ bazel_module: { bp2build_available: true },
+}
+` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
+ "deps": `[":foo_export"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHeadersExportedSharedLibHeadersReexported(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_headers exported_shared_lib_headers is reexported",
+ ModuleTypeUnderTest: "cc_library_headers",
+ ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryHeadersPreamble + `
+cc_library_headers {
+ name: "foo_headers",
+ export_shared_lib_headers: ["foo_export"],
+ shared_libs: ["foo_export", "foo_no_reexport"],
+ bazel_module: { bp2build_available: true },
+}
+` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
+ "deps": `[":foo_export"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHeadersExportedHeaderLibHeadersReexported(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_headers exported_header_lib_headers is reexported",
+ ModuleTypeUnderTest: "cc_library_headers",
+ ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryHeadersPreamble + `
+cc_library_headers {
+ name: "foo_headers",
+ export_header_lib_headers: ["foo_export"],
+ header_libs: ["foo_export", "foo_no_reexport"],
+ bazel_module: { bp2build_available: true },
+}
+` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
+ "deps": `[":foo_export"]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 7c2c100..6a47862 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -35,17 +35,17 @@
ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
}
-func runCcLibrarySharedTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcLibrarySharedTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "cc_library_shared"
- (&tc).moduleTypeUnderTestFactory = cc.LibrarySharedFactory
- runBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc)
+ (&tc).ModuleTypeUnderTest = "cc_library_shared"
+ (&tc).ModuleTypeUnderTestFactory = cc.LibrarySharedFactory
+ RunBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc)
}
func TestCcLibrarySharedSimple(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared simple overall test",
- filesystem: map[string]string{
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared simple overall test",
+ Filesystem: map[string]string{
// NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
"include_dir_1/include_dir_1_a.h": "",
"include_dir_1/include_dir_1_b.h": "",
@@ -65,7 +65,7 @@
"implicit_include_1.h": "",
"implicit_include_2.h": "",
},
- blueprint: soongCcLibrarySharedPreamble + `
+ Blueprint: soongCcLibrarySharedPreamble + `
cc_library_headers {
name: "header_lib_1",
export_include_dirs: ["header_lib_1"],
@@ -141,8 +141,8 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
"absolute_includes": `[
"include_dir_1",
"include_dir_2",
@@ -184,10 +184,10 @@
}
func TestCcLibrarySharedArchSpecificSharedLib(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared arch-specific shared_libs with whole_static_libs",
- filesystem: map[string]string{},
- blueprint: soongCcLibrarySharedPreamble + `
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared arch-specific shared_libs with whole_static_libs",
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibrarySharedPreamble + `
cc_library_static {
name: "static_dep",
bazel_module: { bp2build_available: false },
@@ -201,8 +201,8 @@
arch: { arm64: { shared_libs: ["shared_dep"], whole_static_libs: ["static_dep"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
"implementation_dynamic_deps": `select({
"//build/bazel/platforms/arch:arm64": [":shared_dep"],
"//conditions:default": [],
@@ -217,10 +217,10 @@
}
func TestCcLibrarySharedOsSpecificSharedLib(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared os-specific shared_libs",
- filesystem: map[string]string{},
- blueprint: soongCcLibrarySharedPreamble + `
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared os-specific shared_libs",
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "shared_dep",
bazel_module: { bp2build_available: false },
@@ -230,8 +230,8 @@
target: { android: { shared_libs: ["shared_dep"], } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
"implementation_dynamic_deps": `select({
"//build/bazel/platforms/os:android": [":shared_dep"],
"//conditions:default": [],
@@ -242,10 +242,10 @@
}
func TestCcLibrarySharedBaseArchOsSpecificSharedLib(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared base, arch, and os-specific shared_libs",
- filesystem: map[string]string{},
- blueprint: soongCcLibrarySharedPreamble + `
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared base, arch, and os-specific shared_libs",
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "shared_dep",
bazel_module: { bp2build_available: false },
@@ -265,8 +265,8 @@
arch: { arm64: { shared_libs: ["shared_dep3"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
"implementation_dynamic_deps": `[":shared_dep"] + select({
"//build/bazel/platforms/arch:arm64": [":shared_dep3"],
"//conditions:default": [],
@@ -280,22 +280,22 @@
}
func TestCcLibrarySharedSimpleExcludeSrcs(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared simple exclude_srcs",
- filesystem: map[string]string{
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared simple exclude_srcs",
+ Filesystem: map[string]string{
"common.c": "",
"foo-a.c": "",
"foo-excluded.c": "",
},
- blueprint: soongCcLibrarySharedPreamble + `
+ Blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "foo_shared",
srcs: ["common.c", "foo-*.c"],
exclude_srcs: ["foo-excluded.c"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
"srcs_c": `[
"common.c",
"foo-a.c",
@@ -306,10 +306,10 @@
}
func TestCcLibrarySharedStrip(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared stripping",
- filesystem: map[string]string{},
- blueprint: soongCcLibrarySharedPreamble + `
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared stripping",
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "foo_shared",
strip: {
@@ -321,8 +321,8 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
"strip": `{
"all": True,
"keep_symbols": False,
@@ -339,19 +339,19 @@
}
func TestCcLibrarySharedVersionScript(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared version script",
- filesystem: map[string]string{
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared version script",
+ Filesystem: map[string]string{
"version_script": "",
},
- blueprint: soongCcLibrarySharedPreamble + `
+ Blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "foo_shared",
version_script: "version_script",
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
"additional_linker_inputs": `["version_script"]`,
"linkopts": `["-Wl,--version-script,$(location version_script)"]`,
}),
@@ -360,12 +360,12 @@
}
func TestCcLibrarySharedNoCrtTrue(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared - nocrt: true emits attribute",
- filesystem: map[string]string{
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared - nocrt: true emits attribute",
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library_shared {
name: "foo_shared",
srcs: ["impl.cpp"],
@@ -373,8 +373,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
"link_crt": `False`,
"srcs": `["impl.cpp"]`,
}),
@@ -383,12 +383,12 @@
}
func TestCcLibrarySharedNoCrtFalse(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared - nocrt: false doesn't emit attribute",
- filesystem: map[string]string{
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared - nocrt: false doesn't emit attribute",
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library_shared {
name: "foo_shared",
srcs: ["impl.cpp"],
@@ -396,8 +396,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
"srcs": `["impl.cpp"]`,
}),
},
@@ -405,12 +405,12 @@
}
func TestCcLibrarySharedNoCrtArchVariant(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared - nocrt in select",
- filesystem: map[string]string{
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared - nocrt in select",
+ Filesystem: map[string]string{
"impl.cpp": "",
},
- blueprint: soongCcLibraryPreamble + `
+ Blueprint: soongCcLibraryPreamble + `
cc_library_shared {
name: "foo_shared",
srcs: ["impl.cpp"],
@@ -425,13 +425,13 @@
include_build_directory: false,
}
`,
- expectedErr: fmt.Errorf("module \"foo_shared\": nocrt is not supported for arch variants"),
+ ExpectedErr: fmt.Errorf("module \"foo_shared\": nocrt is not supported for arch variants"),
})
}
func TestCcLibrarySharedProto(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- blueprint: soongCcProtoPreamble + `cc_library_shared {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Blueprint: soongCcProtoPreamble + `cc_library_shared {
name: "foo",
srcs: ["foo.proto"],
proto: {
@@ -439,12 +439,12 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
"srcs": `["foo.proto"]`,
- }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
"deps": `[":foo_proto"]`,
- }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ }), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":foo_cc_proto_lite"]`,
}),
@@ -453,14 +453,14 @@
}
func TestCcLibrarySharedUseVersionLib(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- blueprint: soongCcProtoPreamble + `cc_library_shared {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Blueprint: soongCcProtoPreamble + `cc_library_shared {
name: "foo",
use_version_lib: true,
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
"use_version_lib": "True",
}),
},
@@ -468,12 +468,12 @@
}
func TestCcLibrarySharedStubs(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared stubs",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- dir: "foo/bar",
- filesystem: map[string]string{
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared stubs",
+ ModuleTypeUnderTest: "cc_library_shared",
+ ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ Dir: "foo/bar",
+ Filesystem: map[string]string{
"foo/bar/Android.bp": `
cc_library_shared {
name: "a",
@@ -483,8 +483,8 @@
}
`,
},
- blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ Blueprint: soongCcLibraryPreamble,
+ ExpectedBazelTargets: []string{makeBazelTarget("cc_library_shared", "a", AttrNameToString{
"stubs_symbol_file": `"a.map.txt"`,
"stubs_versions": `[
"28",
@@ -498,11 +498,11 @@
}
func TestCcLibrarySharedSystemSharedLibsSharedEmpty(t *testing.T) {
- runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared system_shared_libs empty shared default",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- blueprint: soongCcLibrarySharedPreamble + `
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared system_shared_libs empty shared default",
+ ModuleTypeUnderTest: "cc_library_shared",
+ ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ Blueprint: soongCcLibrarySharedPreamble + `
cc_defaults {
name: "empty_defaults",
shared: {
@@ -515,8 +515,112 @@
defaults: ["empty_defaults"],
}
`,
- expectedBazelTargets: []string{makeBazelTarget("cc_library_shared", "empty", attrNameToString{
+ ExpectedBazelTargets: []string{makeBazelTarget("cc_library_shared", "empty", AttrNameToString{
"system_dynamic_deps": "[]",
})},
})
}
+
+func TestCcLibrarySharedConvertLex(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared with lex files",
+ ModuleTypeUnderTest: "cc_library_shared",
+ ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ Filesystem: map[string]string{
+ "foo.c": "",
+ "bar.cc": "",
+ "foo1.l": "",
+ "bar1.ll": "",
+ "foo2.l": "",
+ "bar2.ll": "",
+ },
+ Blueprint: `cc_library_shared {
+ name: "foo_lib",
+ srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
+ lex: { flags: ["--foo_flags"] },
+ include_build_directory: false,
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("genlex", "foo_lib_genlex_l", AttrNameToString{
+ "srcs": `[
+ "foo1.l",
+ "foo2.l",
+ ]`,
+ "lexopts": `["--foo_flags"]`,
+ }),
+ makeBazelTarget("genlex", "foo_lib_genlex_ll", AttrNameToString{
+ "srcs": `[
+ "bar1.ll",
+ "bar2.ll",
+ ]`,
+ "lexopts": `["--foo_flags"]`,
+ }),
+ makeBazelTarget("cc_library_shared", "foo_lib", AttrNameToString{
+ "srcs": `[
+ "bar.cc",
+ ":foo_lib_genlex_ll",
+ ]`,
+ "srcs_c": `[
+ "foo.c",
+ ":foo_lib_genlex_l",
+ ]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedClangUnknownFlags(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Blueprint: soongCcProtoPreamble + `cc_library_shared {
+ name: "foo",
+ conlyflags: ["-a", "-finline-functions"],
+ cflags: ["-b","-finline-functions"],
+ cppflags: ["-c", "-finline-functions"],
+ ldflags: ["-d","-finline-functions", "-e"],
+ include_build_directory: false,
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "conlyflags": `["-a"]`,
+ "copts": `["-b"]`,
+ "cppflags": `["-c"]`,
+ "linkopts": `[
+ "-d",
+ "-e",
+ ]`,
+ }),
+ },
+ })
+}
+
+func TestCCLibraryFlagSpaceSplitting(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Blueprint: soongCcProtoPreamble + `cc_library_shared {
+ name: "foo",
+ conlyflags: [ "-include header.h"],
+ cflags: ["-include header.h"],
+ cppflags: ["-include header.h"],
+ version_script: "version_script",
+ include_build_directory: false,
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "additional_linker_inputs": `["version_script"]`,
+ "conlyflags": `[
+ "-include",
+ "header.h",
+ ]`,
+ "copts": `[
+ "-include",
+ "header.h",
+ ]`,
+ "cppflags": `[
+ "-include",
+ "header.h",
+ ]`,
+ "linkopts": `["-Wl,--version-script,$(location version_script)"]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index be10e86..ddb7bf9 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -18,6 +18,7 @@
"android/soong/android"
"android/soong/cc"
"android/soong/genrule"
+ "fmt"
"testing"
)
@@ -64,18 +65,18 @@
ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
}
-func runCcLibraryStaticTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcLibraryStaticTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "cc_library_static"
- (&tc).moduleTypeUnderTestFactory = cc.LibraryStaticFactory
- runBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc)
+ (&tc).ModuleTypeUnderTest = "cc_library_static"
+ (&tc).ModuleTypeUnderTestFactory = cc.LibraryStaticFactory
+ RunBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc)
}
func TestCcLibraryStaticSimple(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static test",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static test",
+ Filesystem: map[string]string{
// NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
"include_dir_1/include_dir_1_a.h": "",
"include_dir_1/include_dir_1_b.h": "",
@@ -95,7 +96,7 @@
"implicit_include_1.h": "",
"implicit_include_2.h": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_headers {
name: "header_lib_1",
export_include_dirs: ["header_lib_1"],
@@ -171,8 +172,8 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"absolute_includes": `[
"include_dir_1",
"include_dir_2",
@@ -204,17 +205,17 @@
":whole_static_lib_1",
":whole_static_lib_2",
]`,
- "sdk_version": `"current"`,
- "min_sdk_version": `"29"`,
+ "sdk_version": `"current"`,
+ "min_sdk_version": `"29"`,
}),
},
})
}
func TestCcLibraryStaticSubpackage(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static subpackage test",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static subpackage test",
+ Filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
"subpackage/subpackage_header.h": "",
@@ -228,7 +229,7 @@
"subpackage/subsubpackage/subsubsubpackage/subsubsubpackage_header.h": "",
"subpackage/subsubpackage/subsubsubpackage/subdirectory/subdirectory_header.h": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: [],
@@ -236,8 +237,8 @@
"subpackage",
],
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"absolute_includes": `["subpackage"]`,
"local_includes": `["."]`,
}),
@@ -246,22 +247,22 @@
}
func TestCcLibraryStaticExportIncludeDir(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static export include dir",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static export include dir",
+ Filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
"subpackage/subpackage_header.h": "",
"subpackage/subdirectory/subdirectory_header.h": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
export_include_dirs: ["subpackage"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"export_includes": `["subpackage"]`,
}),
},
@@ -269,22 +270,22 @@
}
func TestCcLibraryStaticExportSystemIncludeDir(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static export system include dir",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static export system include dir",
+ Filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
"subpackage/subpackage_header.h": "",
"subpackage/subdirectory/subdirectory_header.h": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
export_system_include_dirs: ["subpackage"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"export_system_includes": `["subpackage"]`,
}),
},
@@ -292,10 +293,10 @@
}
func TestCcLibraryStaticManyIncludeDirs(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
- dir: "subpackage",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
+ Dir: "subpackage",
+ Filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": `
cc_library_static {
@@ -317,9 +318,9 @@
"subpackage2/header.h": "",
"subpackage3/subsubpackage/header.h": "",
},
- blueprint: soongCcLibraryStaticPreamble,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ Blueprint: soongCcLibraryStaticPreamble,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"absolute_includes": `[
"subpackage/subsubpackage",
"subpackage2",
@@ -335,23 +336,23 @@
}
func TestCcLibraryStaticIncludeBuildDirectoryDisabled(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static include_build_directory disabled",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static include_build_directory disabled",
+ Filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
"subpackage/subpackage_header.h": "",
"subpackage/subdirectory/subdirectory_header.h": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
include_dirs: ["subpackage"], // still used, but local_include_dirs is recommended
local_include_dirs: ["subpackage2"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"absolute_includes": `["subpackage"]`,
"local_includes": `["subpackage2"]`,
}),
@@ -360,9 +361,9 @@
}
func TestCcLibraryStaticIncludeBuildDirectoryEnabled(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static include_build_directory enabled",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static include_build_directory enabled",
+ Filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
"subpackage/subpackage_header.h": "",
@@ -370,15 +371,15 @@
"subpackage2/subpackage2_header.h": "",
"subpackage/subdirectory/subdirectory_header.h": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
include_dirs: ["subpackage"], // still used, but local_include_dirs is recommended
local_include_dirs: ["subpackage2"],
include_build_directory: true,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"absolute_includes": `["subpackage"]`,
"local_includes": `[
"subpackage2",
@@ -390,10 +391,10 @@
}
func TestCcLibraryStaticArchSpecificStaticLib(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch-specific static_libs",
- filesystem: map[string]string{},
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static arch-specific static_libs",
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
bazel_module: { bp2build_available: false },
@@ -407,8 +408,8 @@
arch: { arm64: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"implementation_deps": `select({
"//build/bazel/platforms/arch:arm64": [":static_dep"],
"//conditions:default": [],
@@ -423,10 +424,10 @@
}
func TestCcLibraryStaticOsSpecificStaticLib(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static os-specific static_libs",
- filesystem: map[string]string{},
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static os-specific static_libs",
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
bazel_module: { bp2build_available: false },
@@ -440,8 +441,8 @@
target: { android: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"implementation_deps": `select({
"//build/bazel/platforms/os:android": [":static_dep"],
"//conditions:default": [],
@@ -456,10 +457,10 @@
}
func TestCcLibraryStaticBaseArchOsSpecificStaticLib(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static base, arch and os-specific static_libs",
- filesystem: map[string]string{},
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static base, arch and os-specific static_libs",
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
bazel_module: { bp2build_available: false },
@@ -484,8 +485,8 @@
arch: { arm64: { static_libs: ["static_dep4"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"implementation_deps": `[":static_dep"] + select({
"//build/bazel/platforms/arch:arm64": [":static_dep4"],
"//conditions:default": [],
@@ -500,22 +501,22 @@
}
func TestCcLibraryStaticSimpleExcludeSrcs(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static simple exclude_srcs",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static simple exclude_srcs",
+ Filesystem: map[string]string{
"common.c": "",
"foo-a.c": "",
"foo-excluded.c": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "foo-*.c"],
exclude_srcs: ["foo-excluded.c"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs_c": `[
"common.c",
"foo-a.c",
@@ -526,21 +527,21 @@
}
func TestCcLibraryStaticOneArchSrcs(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch specific srcs",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static one arch specific srcs",
+ Filesystem: map[string]string{
"common.c": "",
"foo-arm.c": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c"],
arch: { arm: { srcs: ["foo-arm.c"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["foo-arm.c"],
"//conditions:default": [],
@@ -551,15 +552,15 @@
}
func TestCcLibraryStaticOneArchSrcsExcludeSrcs(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch specific srcs and exclude_srcs",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static one arch specific srcs and exclude_srcs",
+ Filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
"not-for-arm.c": "",
"not-for-anything.c": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -569,8 +570,8 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["for-arm.c"],
"//conditions:default": ["not-for-arm.c"],
@@ -581,16 +582,16 @@
}
func TestCcLibraryStaticTwoArchExcludeSrcs(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch specific exclude_srcs for 2 architectures",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static arch specific exclude_srcs for 2 architectures",
+ Filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
"for-x86.c": "",
"not-for-arm.c": "",
"not-for-x86.c": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -601,8 +602,8 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-x86.c",
@@ -623,9 +624,9 @@
}
func TestCcLibraryStaticFourArchExcludeSrcs(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch specific exclude_srcs for 4 architectures",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static arch specific exclude_srcs for 4 architectures",
+ Filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
"for-arm64.c": "",
@@ -637,7 +638,7 @@
"not-for-x86_64.c": "",
"not-for-everything.c": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -650,8 +651,8 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-arm64.c",
@@ -690,14 +691,14 @@
}
func TestCcLibraryStaticOneArchEmpty(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch empty",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static one arch empty",
+ Filesystem: map[string]string{
"common.cc": "",
"foo-no-arm.cc": "",
"foo-excluded.cc": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.cc", "foo-*.cc"],
@@ -707,8 +708,8 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs": `["common.cc"] + select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": ["foo-no-arm.cc"],
@@ -719,15 +720,15 @@
}
func TestCcLibraryStaticOneArchEmptyOtherSet(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch empty other set",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static one arch empty other set",
+ Filesystem: map[string]string{
"common.cc": "",
"foo-no-arm.cc": "",
"x86-only.cc": "",
"foo-excluded.cc": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.cc", "foo-*.cc"],
@@ -738,8 +739,8 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs": `["common.cc"] + select({
"//build/bazel/platforms/arch:arm": [],
"//build/bazel/platforms/arch:x86": [
@@ -754,10 +755,10 @@
}
func TestCcLibraryStaticMultipleDepSameName(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static multiple dep same name panic",
- filesystem: map[string]string{},
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static multiple dep same name panic",
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
bazel_module: { bp2build_available: false },
@@ -767,8 +768,8 @@
static_libs: ["static_dep", "static_dep"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"implementation_deps": `[":static_dep"]`,
}),
},
@@ -776,14 +777,14 @@
}
func TestCcLibraryStaticOneMultilibSrcsExcludeSrcs(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static 1 multilib srcs and exclude_srcs",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static 1 multilib srcs and exclude_srcs",
+ Filesystem: map[string]string{
"common.c": "",
"for-lib32.c": "",
"not-for-lib32.c": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -792,8 +793,8 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["for-lib32.c"],
"//build/bazel/platforms/arch:x86": ["for-lib32.c"],
@@ -805,16 +806,16 @@
}
func TestCcLibraryStaticTwoMultilibSrcsExcludeSrcs(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static 2 multilib srcs and exclude_srcs",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static 2 multilib srcs and exclude_srcs",
+ Filesystem: map[string]string{
"common.c": "",
"for-lib32.c": "",
"for-lib64.c": "",
"not-for-lib32.c": "",
"not-for-lib64.c": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -824,8 +825,8 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-lib64.c",
@@ -854,9 +855,9 @@
}
func TestCcLibrarySTaticArchMultilibSrcsExcludeSrcs(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch and multilib srcs and exclude_srcs",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static arch and multilib srcs and exclude_srcs",
+ Filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
"for-arm64.c": "",
@@ -872,7 +873,7 @@
"not-for-lib64.c": "",
"not-for-everything.c": "",
},
- blueprint: soongCcLibraryStaticPreamble + `
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -889,8 +890,8 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-arm64.c",
@@ -939,8 +940,8 @@
}
func TestCcLibraryStaticGeneratedHeadersAllPartitions(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Blueprint: soongCcLibraryStaticPreamble + `
genrule {
name: "generated_hdr",
cmd: "nothing to see here",
@@ -960,8 +961,8 @@
export_generated_headers: ["export_generated_hdr"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"export_includes": `["."]`,
"local_includes": `["."]`,
"hdrs": `[":export_generated_hdr"]`,
@@ -983,9 +984,9 @@
}
func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch srcs/exclude_srcs with generated files",
- filesystem: map[string]string{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static arch srcs/exclude_srcs with generated files",
+ Filesystem: map[string]string{
"common.cpp": "",
"for-x86.cpp": "",
"not-for-x86.cpp": "",
@@ -996,7 +997,7 @@
simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_x86") +
simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_android"),
},
- blueprint: soongCcLibraryStaticPreamble +
+ Blueprint: soongCcLibraryStaticPreamble +
simpleModuleDoNotConvertBp2build("genrule", "generated_src") +
simpleModuleDoNotConvertBp2build("genrule", "generated_src_not_x86") +
simpleModuleDoNotConvertBp2build("genrule", "generated_src_android") +
@@ -1028,8 +1029,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs": `[
"common.cpp",
":generated_src",
@@ -1060,10 +1061,10 @@
}
func TestCcLibraryStaticGetTargetProperties(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
- description: "cc_library_static complex GetTargetProperties",
- blueprint: soongCcLibraryStaticPreamble + `
+ Description: "cc_library_static complex GetTargetProperties",
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
target: {
@@ -1091,8 +1092,8 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"srcs_c": `select({
"//build/bazel/platforms/os:android": ["android_src.c"],
"//conditions:default": [],
@@ -1111,9 +1112,9 @@
}
func TestCcLibraryStaticProductVariableSelects(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static product variable selects",
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static product variable selects",
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c"],
@@ -1130,8 +1131,8 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"copts": `select({
"//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"],
"//conditions:default": [],
@@ -1149,10 +1150,10 @@
}
func TestCcLibraryStaticProductVariableArchSpecificSelects(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch-specific product variable selects",
- filesystem: map[string]string{},
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static arch-specific product variable selects",
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c"],
@@ -1190,8 +1191,8 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"copts": `select({
"//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
"//conditions:default": [],
@@ -1215,10 +1216,10 @@
}
func TestCcLibraryStaticProductVariableStringReplacement(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static product variable string replacement",
- filesystem: map[string]string{},
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static product variable string replacement",
+ Filesystem: map[string]string{},
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.S"],
@@ -1229,8 +1230,8 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"asflags": `select({
"//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
"//conditions:default": [],
@@ -1242,17 +1243,17 @@
}
func TestStaticLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty root",
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static system_shared_lib empty root",
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "root_empty",
system_shared_libs: [],
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "root_empty", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "root_empty", AttrNameToString{
"system_dynamic_deps": `[]`,
}),
},
@@ -1260,9 +1261,9 @@
}
func TestStaticLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty static default",
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static system_shared_lib empty static default",
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_defaults {
name: "static_empty_defaults",
static: {
@@ -1275,8 +1276,8 @@
defaults: ["static_empty_defaults"],
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "static_empty", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "static_empty", AttrNameToString{
"system_dynamic_deps": `[]`,
}),
},
@@ -1284,9 +1285,9 @@
}
func TestStaticLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty for bionic variant",
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static system_shared_lib empty for bionic variant",
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "target_bionic_empty",
target: {
@@ -1297,8 +1298,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "target_bionic_empty", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_bionic_empty", AttrNameToString{
"system_dynamic_deps": `[]`,
}),
},
@@ -1310,9 +1311,9 @@
// The correct behavior would be if bp2build wrote `system_dynamic_deps = []`
// only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
// b/195791252 tracks the fix.
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty for linux_bionic variant",
- blueprint: soongCcLibraryStaticPreamble + `
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static system_shared_lib empty for linux_bionic variant",
+ Blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "target_linux_bionic_empty",
target: {
@@ -1323,8 +1324,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "target_linux_bionic_empty", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_linux_bionic_empty", AttrNameToString{
"system_dynamic_deps": `[]`,
}),
},
@@ -1332,9 +1333,9 @@
}
func TestStaticLibrary_SystemSharedLibsBionic(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_libs set for bionic variant",
- blueprint: soongCcLibraryStaticPreamble +
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static system_shared_libs set for bionic variant",
+ Blueprint: soongCcLibraryStaticPreamble +
simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
cc_library_static {
name: "target_bionic",
@@ -1346,8 +1347,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "target_bionic", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_bionic", AttrNameToString{
"system_dynamic_deps": `select({
"//build/bazel/platforms/os:android": [":libc"],
"//build/bazel/platforms/os:linux_bionic": [":libc"],
@@ -1359,9 +1360,9 @@
}
func TestStaticLibrary_SystemSharedLibsLinuxRootAndLinuxBionic(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
- blueprint: soongCcLibraryStaticPreamble +
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
+ Blueprint: soongCcLibraryStaticPreamble +
simpleModuleDoNotConvertBp2build("cc_library", "libc") +
simpleModuleDoNotConvertBp2build("cc_library", "libm") + `
cc_library_static {
@@ -1375,8 +1376,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "target_linux_bionic", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_linux_bionic", AttrNameToString{
"system_dynamic_deps": `[":libc"] + select({
"//build/bazel/platforms/os:linux_bionic": [":libm"],
"//conditions:default": [],
@@ -1387,9 +1388,9 @@
}
func TestCcLibrarystatic_SystemSharedLibUsedAsDep(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty for linux_bionic variant",
- blueprint: soongCcLibraryStaticPreamble +
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static system_shared_lib empty for linux_bionic variant",
+ Blueprint: soongCcLibraryStaticPreamble +
simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
cc_library_static {
name: "used_in_bionic_oses",
@@ -1417,26 +1418,26 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "all", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "all", AttrNameToString{
"implementation_dynamic_deps": `select({
"//build/bazel/platforms/os:android": [],
"//build/bazel/platforms/os:linux_bionic": [],
"//conditions:default": [":libc"],
})`,
}),
- makeBazelTarget("cc_library_static", "keep_for_empty_system_shared_libs", attrNameToString{
+ makeBazelTarget("cc_library_static", "keep_for_empty_system_shared_libs", AttrNameToString{
"implementation_dynamic_deps": `[":libc"]`,
"system_dynamic_deps": `[]`,
}),
- makeBazelTarget("cc_library_static", "used_in_bionic_oses", attrNameToString{}),
+ makeBazelTarget("cc_library_static", "used_in_bionic_oses", AttrNameToString{}),
},
})
}
func TestCcLibraryStaticProto(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- blueprint: soongCcProtoPreamble + `cc_library_static {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Blueprint: soongCcProtoPreamble + `cc_library_static {
name: "foo",
srcs: ["foo.proto"],
proto: {
@@ -1444,12 +1445,12 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
"srcs": `["foo.proto"]`,
- }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
"deps": `[":foo_proto"]`,
- }), makeBazelTarget("cc_library_static", "foo", attrNameToString{
+ }), makeBazelTarget("cc_library_static", "foo", AttrNameToString{
"deps": `[":libprotobuf-cpp-lite"]`,
"whole_archive_deps": `[":foo_cc_proto_lite"]`,
}),
@@ -1458,14 +1459,14 @@
}
func TestCcLibraryStaticUseVersionLib(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- blueprint: soongCcProtoPreamble + `cc_library_static {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Blueprint: soongCcProtoPreamble + `cc_library_static {
name: "foo",
use_version_lib: true,
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo", AttrNameToString{
"use_version_lib": "True",
}),
},
@@ -1473,19 +1474,88 @@
}
func TestCcLibraryStaticStdInFlags(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- blueprint: soongCcProtoPreamble + `cc_library_static {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Blueprint: soongCcProtoPreamble + `cc_library_static {
name: "foo",
cflags: ["-std=candcpp"],
conlyflags: ["-std=conly"],
cppflags: ["-std=cpp"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_library_static", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo", AttrNameToString{
"conlyflags": `["-std=conly"]`,
"cppflags": `["-std=cpp"]`,
}),
},
})
}
+
+func TestCcLibraryStaticStl(t *testing.T) {
+ testCases := []struct {
+ desc string
+ prop string
+ attr AttrNameToString
+ }{
+ {
+ desc: "c++_shared deduped to libc++",
+ prop: `stl: "c++_shared",`,
+ attr: AttrNameToString{
+ "stl": `"libc++"`,
+ },
+ },
+ {
+ desc: "libc++ to libc++",
+ prop: `stl: "libc++",`,
+ attr: AttrNameToString{
+ "stl": `"libc++"`,
+ },
+ },
+ {
+ desc: "c++_static to libc++_static",
+ prop: `stl: "c++_static",`,
+ attr: AttrNameToString{
+ "stl": `"libc++_static"`,
+ },
+ },
+ {
+ desc: "libc++_static to libc++_static",
+ prop: `stl: "libc++_static",`,
+ attr: AttrNameToString{
+ "stl": `"libc++_static"`,
+ },
+ },
+ {
+ desc: "system to system",
+ prop: `stl: "system",`,
+ attr: AttrNameToString{
+ "stl": `"system"`,
+ },
+ },
+ {
+ desc: "none to none",
+ prop: `stl: "none",`,
+ attr: AttrNameToString{
+ "stl": `"none"`,
+ },
+ },
+ {
+ desc: "empty to empty",
+ attr: AttrNameToString{},
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(*testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Blueprint: fmt.Sprintf(`cc_library_static {
+ name: "foo",
+ include_build_directory: false,
+ %s
+}`, tc.prop),
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo", tc.attr),
+ },
+ })
+ })
+ }
+}
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index ea58086..37d5580 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -26,23 +26,23 @@
ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
}
-func runCcObjectTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcObjectTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "cc_object"
- (&tc).moduleTypeUnderTestFactory = cc.ObjectFactory
- runBp2BuildTestCase(t, registerCcObjectModuleTypes, tc)
+ (&tc).ModuleTypeUnderTest = "cc_object"
+ (&tc).ModuleTypeUnderTestFactory = cc.ObjectFactory
+ RunBp2BuildTestCase(t, registerCcObjectModuleTypes, tc)
}
func TestCcObjectSimple(t *testing.T) {
- runCcObjectTestCase(t, bp2buildTestCase{
- description: "simple cc_object generates cc_object with include header dep",
- filesystem: map[string]string{
+ runCcObjectTestCase(t, Bp2buildTestCase{
+ Description: "simple cc_object generates cc_object with include header dep",
+ Filesystem: map[string]string{
"a/b/foo.h": "",
"a/b/bar.h": "",
"a/b/exclude.c": "",
"a/b/c.c": "",
},
- blueprint: `cc_object {
+ Blueprint: `cc_object {
name: "foo",
local_include_dirs: ["include"],
system_shared_libs: [],
@@ -59,8 +59,8 @@
min_sdk_version: "29",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_object", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", AttrNameToString{
"copts": `[
"-fno-addrsig",
"-Wno-gcc-compat",
@@ -73,16 +73,16 @@
]`,
"srcs": `["a/b/c.c"]`,
"system_dynamic_deps": `[]`,
- "sdk_version": `"current"`,
- "min_sdk_version": `"29"`,
+ "sdk_version": `"current"`,
+ "min_sdk_version": `"29"`,
}),
},
})
}
func TestCcObjectDefaults(t *testing.T) {
- runCcObjectTestCase(t, bp2buildTestCase{
- blueprint: `cc_object {
+ runCcObjectTestCase(t, Bp2buildTestCase{
+ Blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
srcs: [
@@ -105,8 +105,8 @@
],
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_object", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", AttrNameToString{
"copts": `[
"-Werror",
"-fno-addrsig",
@@ -119,13 +119,13 @@
}
func TestCcObjectCcObjetDepsInObjs(t *testing.T) {
- runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object with cc_object deps in objs props",
- filesystem: map[string]string{
+ runCcObjectTestCase(t, Bp2buildTestCase{
+ Description: "cc_object with cc_object deps in objs props",
+ Filesystem: map[string]string{
"a/b/c.c": "",
"x/y/z.c": "",
},
- blueprint: `cc_object {
+ Blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
srcs: ["a/b/c.c"],
@@ -140,12 +140,12 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_object", "bar", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "bar", AttrNameToString{
"copts": `["-fno-addrsig"]`,
"srcs": `["x/y/z.c"]`,
"system_dynamic_deps": `[]`,
- }), makeBazelTarget("cc_object", "foo", attrNameToString{
+ }), makeBazelTarget("cc_object", "foo", AttrNameToString{
"copts": `["-fno-addrsig"]`,
"deps": `[":bar"]`,
"srcs": `["a/b/c.c"]`,
@@ -156,21 +156,21 @@
}
func TestCcObjectIncludeBuildDirFalse(t *testing.T) {
- runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object with include_build_dir: false",
- filesystem: map[string]string{
+ runCcObjectTestCase(t, Bp2buildTestCase{
+ Description: "cc_object with include_build_dir: false",
+ Filesystem: map[string]string{
"a/b/c.c": "",
"x/y/z.c": "",
},
- blueprint: `cc_object {
+ Blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
srcs: ["a/b/c.c"],
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_object", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", AttrNameToString{
"copts": `["-fno-addrsig"]`,
"srcs": `["a/b/c.c"]`,
"system_dynamic_deps": `[]`,
@@ -180,9 +180,9 @@
}
func TestCcObjectProductVariable(t *testing.T) {
- runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object with product variable",
- blueprint: `cc_object {
+ runCcObjectTestCase(t, Bp2buildTestCase{
+ Description: "cc_object with product variable",
+ Blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
include_build_directory: false,
@@ -194,8 +194,8 @@
srcs: ["src.S"],
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_object", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", AttrNameToString{
"asflags": `select({
"//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
"//conditions:default": [],
@@ -209,9 +209,9 @@
}
func TestCcObjectCflagsOneArch(t *testing.T) {
- runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting cflags for one arch",
- blueprint: `cc_object {
+ runCcObjectTestCase(t, Bp2buildTestCase{
+ Description: "cc_object setting cflags for one arch",
+ Blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
srcs: ["a.cpp"],
@@ -226,8 +226,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_object", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", AttrNameToString{
"copts": `["-fno-addrsig"] + select({
"//build/bazel/platforms/arch:x86": ["-fPIC"],
"//conditions:default": [],
@@ -243,9 +243,9 @@
}
func TestCcObjectCflagsFourArch(t *testing.T) {
- runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting cflags for 4 architectures",
- blueprint: `cc_object {
+ runCcObjectTestCase(t, Bp2buildTestCase{
+ Description: "cc_object setting cflags for 4 architectures",
+ Blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
srcs: ["base.cpp"],
@@ -270,8 +270,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_object", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", AttrNameToString{
"copts": `["-fno-addrsig"] + select({
"//build/bazel/platforms/arch:arm": ["-Wall"],
"//build/bazel/platforms/arch:arm64": ["-Wall"],
@@ -293,17 +293,17 @@
}
func TestCcObjectLinkerScript(t *testing.T) {
- runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting linker_script",
- blueprint: `cc_object {
+ runCcObjectTestCase(t, Bp2buildTestCase{
+ Description: "cc_object setting linker_script",
+ Blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
linker_script: "bunny.lds",
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_object", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", AttrNameToString{
"copts": `["-fno-addrsig"]`,
"linker_script": `"bunny.lds"`,
"srcs": `["base.cpp"]`,
@@ -313,9 +313,9 @@
}
func TestCcObjectDepsAndLinkerScriptSelects(t *testing.T) {
- runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting deps and linker_script across archs",
- blueprint: `cc_object {
+ runCcObjectTestCase(t, Bp2buildTestCase{
+ Description: "cc_object setting deps and linker_script across archs",
+ Blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
arch: {
@@ -359,8 +359,8 @@
bazel_module: { bp2build_available: false },
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_object", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", AttrNameToString{
"copts": `["-fno-addrsig"]`,
"deps": `select({
"//build/bazel/platforms/arch:arm": [":arm_obj"],
@@ -381,9 +381,9 @@
}
func TestCcObjectSelectOnLinuxAndBionicArchs(t *testing.T) {
- runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting srcs based on linux and bionic archs",
- blueprint: `cc_object {
+ runCcObjectTestCase(t, Bp2buildTestCase{
+ Description: "cc_object setting srcs based on linux and bionic archs",
+ Blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
target: {
@@ -400,8 +400,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("cc_object", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", AttrNameToString{
"copts": `["-fno-addrsig"]`,
"srcs": `["base.cpp"] + select({
"//build/bazel/platforms/os_arch:android_arm64": [
@@ -414,6 +414,7 @@
"bionic_arm64.cpp",
],
"//build/bazel/platforms/os_arch:linux_glibc_x86": ["linux_x86.cpp"],
+ "//build/bazel/platforms/os_arch:linux_musl_arm64": ["linux_arm64.cpp"],
"//build/bazel/platforms/os_arch:linux_musl_x86": ["linux_x86.cpp"],
"//conditions:default": [],
})`,
diff --git a/bp2build/cc_prebuilt_library_conversion_test.go b/bp2build/cc_prebuilt_library_conversion_test.go
index 3cf8969..74ad005 100644
--- a/bp2build/cc_prebuilt_library_conversion_test.go
+++ b/bp2build/cc_prebuilt_library_conversion_test.go
@@ -22,24 +22,24 @@
func TestPrebuiltLibraryStaticAndSharedSimple(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library static and shared simple",
- moduleTypeUnderTest: "cc_prebuilt_library",
- moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library static and shared simple",
+ ModuleTypeUnderTest: "cc_prebuilt_library",
+ ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library {
name: "libtest",
srcs: ["libf.so"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
"static_library": `"libf.so"`,
}),
- makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+ makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
"shared_library": `"libf.so"`,
}),
},
@@ -48,15 +48,15 @@
func TestPrebuiltLibraryWithArchVariance(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library with arch variance",
- moduleTypeUnderTest: "cc_prebuilt_library",
- moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library with arch variance",
+ ModuleTypeUnderTest: "cc_prebuilt_library",
+ ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library {
name: "libtest",
arch: {
@@ -65,15 +65,15 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
"static_library": `select({
"//build/bazel/platforms/arch:arm": "libg.so",
"//build/bazel/platforms/arch:arm64": "libf.so",
"//conditions:default": None,
})`,
}),
- makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+ makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
"shared_library": `select({
"//build/bazel/platforms/arch:arm": "libg.so",
"//build/bazel/platforms/arch:arm64": "libf.so",
@@ -86,16 +86,16 @@
func TestPrebuiltLibraryAdditionalAttrs(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library additional attributes",
- moduleTypeUnderTest: "cc_prebuilt_library",
- moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library additional attributes",
+ ModuleTypeUnderTest: "cc_prebuilt_library",
+ ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
"testdir/1/": "",
"testdir/2/": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library {
name: "libtest",
srcs: ["libf.so"],
@@ -103,14 +103,14 @@
export_system_include_dirs: ["testdir/2/"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
"static_library": `"libf.so"`,
"export_includes": `["testdir/1/"]`,
"export_system_includes": `["testdir/2/"]`,
}),
// TODO(b/229374533): When fixed, update this test
- makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+ makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
"shared_library": `"libf.so"`,
}),
},
@@ -119,15 +119,15 @@
func TestPrebuiltLibrarySharedStanzaFails(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library with shared stanza fails because multiple sources",
- moduleTypeUnderTest: "cc_prebuilt_library",
- moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library with shared stanza fails because multiple sources",
+ ModuleTypeUnderTest: "cc_prebuilt_library",
+ ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library {
name: "libtest",
srcs: ["libf.so"],
@@ -136,21 +136,21 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedErr: fmt.Errorf("Expected at most one source file"),
+ ExpectedErr: fmt.Errorf("Expected at most one source file"),
})
}
func TestPrebuiltLibraryStaticStanzaFails(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library with static stanza fails because multiple sources",
- moduleTypeUnderTest: "cc_prebuilt_library",
- moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library with static stanza fails because multiple sources",
+ ModuleTypeUnderTest: "cc_prebuilt_library",
+ ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library {
name: "libtest",
srcs: ["libf.so"],
@@ -159,21 +159,21 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedErr: fmt.Errorf("Expected at most one source file"),
+ ExpectedErr: fmt.Errorf("Expected at most one source file"),
})
}
func TestPrebuiltLibrarySharedAndStaticStanzas(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library with both shared and static stanzas",
- moduleTypeUnderTest: "cc_prebuilt_library",
- moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library with both shared and static stanzas",
+ ModuleTypeUnderTest: "cc_prebuilt_library",
+ ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library {
name: "libtest",
static: {
@@ -184,11 +184,11 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
"static_library": `"libf.so"`,
}),
- makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+ makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
"shared_library": `"libg.so"`,
}),
},
diff --git a/bp2build/cc_prebuilt_library_shared_test.go b/bp2build/cc_prebuilt_library_shared_test.go
index 57905e5..bcf0ce2 100644
--- a/bp2build/cc_prebuilt_library_shared_test.go
+++ b/bp2build/cc_prebuilt_library_shared_test.go
@@ -9,21 +9,21 @@
func TestSharedPrebuiltLibrary(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library shared simple",
- moduleTypeUnderTest: "cc_prebuilt_library_shared",
- moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library shared simple",
+ ModuleTypeUnderTest: "cc_prebuilt_library_shared",
+ ModuleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library_shared {
name: "libtest",
srcs: ["libf.so"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
"shared_library": `"libf.so"`,
}),
},
@@ -32,15 +32,15 @@
func TestSharedPrebuiltLibraryWithArchVariance(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library shared with arch variance",
- moduleTypeUnderTest: "cc_prebuilt_library_shared",
- moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library shared with arch variance",
+ ModuleTypeUnderTest: "cc_prebuilt_library_shared",
+ ModuleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library_shared {
name: "libtest",
arch: {
@@ -49,8 +49,8 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
"shared_library": `select({
"//build/bazel/platforms/arch:arm": "libg.so",
"//build/bazel/platforms/arch:arm64": "libf.so",
@@ -63,15 +63,15 @@
func TestSharedPrebuiltLibrarySharedStanzaFails(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library shared with shared stanza fails because multiple sources",
- moduleTypeUnderTest: "cc_prebuilt_library_shared",
- moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library shared with shared stanza fails because multiple sources",
+ ModuleTypeUnderTest: "cc_prebuilt_library_shared",
+ ModuleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library_shared {
name: "libtest",
srcs: ["libf.so"],
@@ -80,6 +80,6 @@
},
bazel_module: { bp2build_available: true},
}`,
- expectedErr: fmt.Errorf("Expected at most one source file"),
+ ExpectedErr: fmt.Errorf("Expected at most one source file"),
})
}
diff --git a/bp2build/cc_prebuilt_library_static_test.go b/bp2build/cc_prebuilt_library_static_test.go
index 3feb1f1..7498e50 100644
--- a/bp2build/cc_prebuilt_library_static_test.go
+++ b/bp2build/cc_prebuilt_library_static_test.go
@@ -22,21 +22,21 @@
func TestStaticPrebuiltLibrary(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library static simple",
- moduleTypeUnderTest: "cc_prebuilt_library_static",
- moduleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library static simple",
+ ModuleTypeUnderTest: "cc_prebuilt_library_static",
+ ModuleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library_static {
name: "libtest",
srcs: ["libf.so"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_library_static", "libtest", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_library_static", "libtest", AttrNameToString{
"static_library": `"libf.so"`,
}),
},
@@ -45,15 +45,15 @@
func TestStaticPrebuiltLibraryWithArchVariance(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library static with arch variance",
- moduleTypeUnderTest: "cc_prebuilt_library_static",
- moduleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library static with arch variance",
+ ModuleTypeUnderTest: "cc_prebuilt_library_static",
+ ModuleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library_static {
name: "libtest",
arch: {
@@ -62,8 +62,8 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_library_static", "libtest", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_library_static", "libtest", AttrNameToString{
"static_library": `select({
"//build/bazel/platforms/arch:arm": "libg.so",
"//build/bazel/platforms/arch:arm64": "libf.so",
@@ -76,15 +76,15 @@
func TestStaticPrebuiltLibraryStaticStanzaFails(t *testing.T) {
runBp2BuildTestCaseSimple(t,
- bp2buildTestCase{
- description: "prebuilt library with static stanza fails because multiple sources",
- moduleTypeUnderTest: "cc_prebuilt_library_static",
- moduleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
- filesystem: map[string]string{
+ Bp2buildTestCase{
+ Description: "prebuilt library with static stanza fails because multiple sources",
+ ModuleTypeUnderTest: "cc_prebuilt_library_static",
+ ModuleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
+ Filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
},
- blueprint: `
+ Blueprint: `
cc_prebuilt_library_static {
name: "libtest",
srcs: ["libf.so"],
@@ -93,6 +93,55 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedErr: fmt.Errorf("Expected at most one source file"),
+ ExpectedErr: fmt.Errorf("Expected at most one source file"),
})
}
+
+func TestCcLibraryStaticConvertLex(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static with lex files",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Filesystem: map[string]string{
+ "foo.c": "",
+ "bar.cc": "",
+ "foo1.l": "",
+ "bar1.ll": "",
+ "foo2.l": "",
+ "bar2.ll": "",
+ },
+ Blueprint: `cc_library_static {
+ name: "foo_lib",
+ srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
+ lex: { flags: ["--foo_flags"] },
+ include_build_directory: false,
+ bazel_module: { bp2build_available: true },
+}`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("genlex", "foo_lib_genlex_l", AttrNameToString{
+ "srcs": `[
+ "foo1.l",
+ "foo2.l",
+ ]`,
+ "lexopts": `["--foo_flags"]`,
+ }),
+ makeBazelTarget("genlex", "foo_lib_genlex_ll", AttrNameToString{
+ "srcs": `[
+ "bar1.ll",
+ "bar2.ll",
+ ]`,
+ "lexopts": `["--foo_flags"]`,
+ }),
+ makeBazelTarget("cc_library_static", "foo_lib", AttrNameToString{
+ "srcs": `[
+ "bar.cc",
+ ":foo_lib_genlex_ll",
+ ]`,
+ "srcs_c": `[
+ "foo.c",
+ ":foo_lib_genlex_l",
+ ]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_yasm_conversion_test.go b/bp2build/cc_yasm_conversion_test.go
new file mode 100644
index 0000000..2a71834
--- /dev/null
+++ b/bp2build/cc_yasm_conversion_test.go
@@ -0,0 +1,179 @@
+// 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/android"
+ "android/soong/cc"
+)
+
+func runYasmTestCase(t *testing.T, tc Bp2buildTestCase) {
+ t.Helper()
+ RunBp2BuildTestCase(t, registerYasmModuleTypes, tc)
+}
+
+func registerYasmModuleTypes(ctx android.RegistrationContext) {
+ cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+ ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
+ ctx.RegisterModuleType("cc_prebuilt_library_static", cc.PrebuiltStaticLibraryFactory)
+ ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+}
+
+func TestYasmSimple(t *testing.T) {
+ runYasmTestCase(t, Bp2buildTestCase{
+ Description: "Simple yasm test",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
+ "main.cpp": "",
+ "myfile.asm": "",
+ },
+ Blueprint: `
+cc_library {
+ name: "foo",
+ srcs: ["main.cpp", "myfile.asm"],
+}`,
+ ExpectedBazelTargets: append([]string{
+ makeBazelTarget("yasm", "foo_yasm", map[string]string{
+ "include_dirs": `["."]`,
+ "srcs": `["myfile.asm"]`,
+ }),
+ }, makeCcLibraryTargets("foo", map[string]string{
+ "local_includes": `["."]`,
+ "srcs": `[
+ "main.cpp",
+ ":foo_yasm",
+ ]`,
+ })...),
+ })
+}
+
+func TestYasmWithIncludeDirs(t *testing.T) {
+ runYasmTestCase(t, Bp2buildTestCase{
+ Description: "Simple yasm test",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
+ "main.cpp": "",
+ "myfile.asm": "",
+ "include1/foo/myinclude.inc": "",
+ "include2/foo/myinclude2.inc": "",
+ },
+ Blueprint: `
+cc_library {
+ name: "foo",
+ local_include_dirs: ["include1/foo"],
+ export_include_dirs: ["include2/foo"],
+ srcs: ["main.cpp", "myfile.asm"],
+}`,
+ ExpectedBazelTargets: append([]string{
+ makeBazelTarget("yasm", "foo_yasm", map[string]string{
+ "include_dirs": `[
+ "include1/foo",
+ ".",
+ "include2/foo",
+ ]`,
+ "srcs": `["myfile.asm"]`,
+ }),
+ }, makeCcLibraryTargets("foo", map[string]string{
+ "local_includes": `[
+ "include1/foo",
+ ".",
+ ]`,
+ "export_includes": `["include2/foo"]`,
+ "srcs": `[
+ "main.cpp",
+ ":foo_yasm",
+ ]`,
+ })...),
+ })
+}
+
+func TestYasmConditionalBasedOnArch(t *testing.T) {
+ runYasmTestCase(t, Bp2buildTestCase{
+ Description: "Simple yasm test",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
+ "main.cpp": "",
+ "myfile.asm": "",
+ },
+ Blueprint: `
+cc_library {
+ name: "foo",
+ srcs: ["main.cpp"],
+ arch: {
+ x86: {
+ srcs: ["myfile.asm"],
+ },
+ },
+}`,
+ ExpectedBazelTargets: append([]string{
+ makeBazelTarget("yasm", "foo_yasm", map[string]string{
+ "include_dirs": `["."]`,
+ "srcs": `select({
+ "//build/bazel/platforms/arch:x86": ["myfile.asm"],
+ "//conditions:default": [],
+ })`,
+ }),
+ }, makeCcLibraryTargets("foo", map[string]string{
+ "local_includes": `["."]`,
+ "srcs": `["main.cpp"] + select({
+ "//build/bazel/platforms/arch:x86": [":foo_yasm"],
+ "//conditions:default": [],
+ })`,
+ })...),
+ })
+}
+
+func TestYasmPartiallyConditional(t *testing.T) {
+ runYasmTestCase(t, Bp2buildTestCase{
+ Description: "Simple yasm test",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Filesystem: map[string]string{
+ "main.cpp": "",
+ "myfile.asm": "",
+ "mysecondfile.asm": "",
+ },
+ Blueprint: `
+cc_library {
+ name: "foo",
+ srcs: ["main.cpp", "myfile.asm"],
+ arch: {
+ x86: {
+ srcs: ["mysecondfile.asm"],
+ },
+ },
+}`,
+ ExpectedBazelTargets: append([]string{
+ makeBazelTarget("yasm", "foo_yasm", map[string]string{
+ "include_dirs": `["."]`,
+ "srcs": `["myfile.asm"] + select({
+ "//build/bazel/platforms/arch:x86": ["mysecondfile.asm"],
+ "//conditions:default": [],
+ })`,
+ }),
+ }, makeCcLibraryTargets("foo", map[string]string{
+ "local_includes": `["."]`,
+ "srcs": `[
+ "main.cpp",
+ ":foo_yasm",
+ ]`,
+ })...),
+ })
+}
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index d37a523..9398d12 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -13,6 +13,30 @@
type selects map[string]reflect.Value
+func getStringValue(str bazel.StringAttribute) (reflect.Value, []selects) {
+ value := reflect.ValueOf(str.Value)
+
+ if !str.HasConfigurableValues() {
+ return value, []selects{}
+ }
+
+ ret := selects{}
+ for _, axis := range str.SortedConfigurationAxes() {
+ configToStrs := str.ConfigurableValues[axis]
+ for config, strs := range configToStrs {
+ selectKey := axis.SelectKey(config)
+ ret[selectKey] = reflect.ValueOf(strs)
+ }
+ }
+ // if there is a select, use the base value as the conditions default value
+ if len(ret) > 0 {
+ ret[bazel.ConditionsDefaultSelectKey] = value
+ value = reflect.Zero(value.Type())
+ }
+
+ return value, []selects{ret}
+}
+
func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
value := reflect.ValueOf(list.Value)
if !list.HasConfigurableValues() {
@@ -137,6 +161,12 @@
// If true, print the default attribute value, even if the attribute is zero.
shouldPrintDefault := false
switch list := v.(type) {
+ case bazel.StringAttribute:
+ if err := list.Collapse(); err != nil {
+ return "", err
+ }
+ value, configurableAttrs = getStringValue(list)
+ defaultSelectValue = &bazelNone
case bazel.StringListAttribute:
value, configurableAttrs = getStringListValues(list)
defaultSelectValue = &emptyBazelList
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 4b013d9..8cf9bea 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -10,6 +10,8 @@
cc_config "android/soong/cc/config"
java_config "android/soong/java/config"
+ "android/soong/apex"
+
"github.com/google/blueprint/proptools"
)
@@ -28,6 +30,9 @@
files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package.
files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg)))
+ files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package.
+ files = append(files, newFile("apex_toolchain", "constants.bzl", apex.BazelApexToolchainVars()))
+
files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n")))
files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String()))
@@ -50,6 +55,7 @@
}
func CreateBazelFiles(
+ cfg android.Config,
ruleShims map[string]RuleShim,
buildToTargets map[string]BazelTargets,
mode CodegenMode) []BazelFile {
@@ -74,16 +80,19 @@
files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
}
- files = append(files, createBuildFiles(buildToTargets, mode)...)
+ files = append(files, createBuildFiles(cfg, buildToTargets, mode)...)
return files
}
-func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
+func createBuildFiles(cfg android.Config, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
files := make([]BazelFile, 0, len(buildToTargets))
+ warnNotWriting := cfg.IsEnvTrue("BP2BUILD_VERBOSE")
for _, dir := range android.SortedStringKeys(buildToTargets) {
if mode == Bp2Build && android.ShouldKeepExistingBuildFileForDir(dir) {
- fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir)
+ if warnNotWriting {
+ fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir)
+ }
continue
}
targets := buildToTargets[dir]
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index e49d855..0cb711c 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -27,7 +27,8 @@
}
func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
- files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
+ files := CreateBazelFiles(android.NullConfig("out", "out/soong"),
+ map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
expectedFilePaths := []bazelFilepath{
{
dir: "",
@@ -103,6 +104,14 @@
basename: "constants.bzl",
},
{
+ dir: "apex_toolchain",
+ basename: GeneratedBuildFileName,
+ },
+ {
+ dir: "apex_toolchain",
+ basename: "constants.bzl",
+ },
+ {
dir: "metrics",
basename: "converted_modules.txt",
},
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index b43cf53..b598b85 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -21,38 +21,38 @@
"testing"
)
-func runFilegroupTestCase(t *testing.T, tc bp2buildTestCase) {
+func runFilegroupTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "filegroup"
- (&tc).moduleTypeUnderTestFactory = android.FileGroupFactory
- runBp2BuildTestCase(t, registerFilegroupModuleTypes, tc)
+ (&tc).ModuleTypeUnderTest = "filegroup"
+ (&tc).ModuleTypeUnderTestFactory = android.FileGroupFactory
+ RunBp2BuildTestCase(t, registerFilegroupModuleTypes, tc)
}
func registerFilegroupModuleTypes(ctx android.RegistrationContext) {}
func TestFilegroupSameNameAsFile_OneFile(t *testing.T) {
- runFilegroupTestCase(t, bp2buildTestCase{
- description: "filegroup - same name as file, with one file",
- filesystem: map[string]string{},
- blueprint: `
+ runFilegroupTestCase(t, Bp2buildTestCase{
+ Description: "filegroup - same name as file, with one file",
+ Filesystem: map[string]string{},
+ Blueprint: `
filegroup {
name: "foo",
srcs: ["foo"],
}
`,
- expectedBazelTargets: []string{}})
+ ExpectedBazelTargets: []string{}})
}
func TestFilegroupSameNameAsFile_MultipleFiles(t *testing.T) {
- runFilegroupTestCase(t, bp2buildTestCase{
- description: "filegroup - same name as file, with multiple files",
- filesystem: map[string]string{},
- blueprint: `
+ runFilegroupTestCase(t, Bp2buildTestCase{
+ Description: "filegroup - same name as file, with multiple files",
+ Filesystem: map[string]string{},
+ Blueprint: `
filegroup {
name: "foo",
srcs: ["foo", "bar"],
}
`,
- expectedErr: fmt.Errorf("filegroup 'foo' cannot contain a file with the same name"),
+ ExpectedErr: fmt.Errorf("filegroup 'foo' cannot contain a file with the same name"),
})
}
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index 9244b99..a8bfecd 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -27,11 +27,11 @@
ctx.RegisterModuleType("genrule_defaults", func() android.Module { return genrule.DefaultsFactory() })
}
-func runGenruleTestCase(t *testing.T, tc bp2buildTestCase) {
+func runGenruleTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "genrule"
- (&tc).moduleTypeUnderTestFactory = genrule.GenRuleFactory
- runBp2BuildTestCase(t, registerGenruleModuleTypes, tc)
+ (&tc).ModuleTypeUnderTest = "genrule"
+ (&tc).ModuleTypeUnderTestFactory = genrule.GenRuleFactory
+ RunBp2BuildTestCase(t, registerGenruleModuleTypes, tc)
}
func otherGenruleBp(genruleTarget string) map[string]string {
@@ -56,6 +56,7 @@
moduleType string
factory android.ModuleFactory
genDir string
+ hod android.HostOrDeviceSupported
}{
{
moduleType: "genrule",
@@ -66,16 +67,19 @@
moduleType: "cc_genrule",
factory: cc.GenRuleFactory,
genDir: "$(RULEDIR)",
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule",
factory: java.GenRuleFactory,
genDir: "$(RULEDIR)",
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule_host",
factory: java.GenRuleFactoryHost,
genDir: "$(RULEDIR)",
+ hod: android.HostSupported,
},
}
@@ -97,31 +101,24 @@
}`
for _, tc := range testCases {
- moduleAttrs := attrNameToString{
+ moduleAttrs := AttrNameToString{
"cmd": fmt.Sprintf(`"$(location :foo.tool) --genDir=%s arg $(SRCS) $(OUTS)"`, tc.genDir),
"outs": `["foo.out"]`,
"srcs": `["foo.in"]`,
"tools": `[":foo.tool"]`,
}
- if tc.moduleType == "java_genrule_host" {
- moduleAttrs["target_compatible_with"] = `select({
- "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
- "//conditions:default": [],
- })`
- }
-
expectedBazelTargets := []string{
- makeBazelTarget("genrule", "foo", moduleAttrs),
+ makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
}
t.Run(tc.moduleType, func(t *testing.T) {
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
- bp2buildTestCase{
- moduleTypeUnderTest: tc.moduleType,
- moduleTypeUnderTestFactory: tc.factory,
- blueprint: fmt.Sprintf(bp, tc.moduleType, tc.moduleType),
- expectedBazelTargets: expectedBazelTargets,
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+ Bp2buildTestCase{
+ ModuleTypeUnderTest: tc.moduleType,
+ ModuleTypeUnderTestFactory: tc.factory,
+ Blueprint: fmt.Sprintf(bp, tc.moduleType, tc.moduleType),
+ ExpectedBazelTargets: expectedBazelTargets,
})
})
}
@@ -131,6 +128,7 @@
testCases := []struct {
moduleType string
factory android.ModuleFactory
+ hod android.HostOrDeviceSupported
}{
{
moduleType: "genrule",
@@ -139,14 +137,17 @@
{
moduleType: "cc_genrule",
factory: cc.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule",
factory: java.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule_host",
factory: java.GenRuleFactoryHost,
+ hod: android.HostSupported,
},
}
@@ -168,13 +169,13 @@
}`
for _, tc := range testCases {
- fooAttrs := attrNameToString{
+ fooAttrs := AttrNameToString{
"cmd": `"$(locations :foo.tools) -s $(OUTS) $(SRCS)"`,
"outs": `["foo.out"]`,
"srcs": `["foo.in"]`,
"tools": `[":foo.tools"]`,
}
- fooToolsAttrs := attrNameToString{
+ fooToolsAttrs := AttrNameToString{
"cmd": `"cp $(SRCS) $(OUTS)"`,
"outs": `[
"foo_tool.out",
@@ -183,27 +184,18 @@
"srcs": `["foo_tool.in"]`,
}
- if tc.moduleType == "java_genrule_host" {
- compatibilityAttrs := `select({
- "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
- "//conditions:default": [],
- })`
- fooAttrs["target_compatible_with"] = compatibilityAttrs
- fooToolsAttrs["target_compatible_with"] = compatibilityAttrs
- }
-
expectedBazelTargets := []string{
- makeBazelTarget("genrule", "foo", fooAttrs),
- makeBazelTarget("genrule", "foo.tools", fooToolsAttrs),
+ makeBazelTargetHostOrDevice("genrule", "foo", fooAttrs, tc.hod),
+ makeBazelTargetHostOrDevice("genrule", "foo.tools", fooToolsAttrs, tc.hod),
}
t.Run(tc.moduleType, func(t *testing.T) {
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
- bp2buildTestCase{
- moduleTypeUnderTest: tc.moduleType,
- moduleTypeUnderTestFactory: tc.factory,
- blueprint: fmt.Sprintf(bp, tc.moduleType, tc.moduleType),
- expectedBazelTargets: expectedBazelTargets,
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+ Bp2buildTestCase{
+ ModuleTypeUnderTest: tc.moduleType,
+ ModuleTypeUnderTestFactory: tc.factory,
+ Blueprint: fmt.Sprintf(bp, tc.moduleType, tc.moduleType),
+ ExpectedBazelTargets: expectedBazelTargets,
})
})
}
@@ -213,6 +205,7 @@
testCases := []struct {
moduleType string
factory android.ModuleFactory
+ hod android.HostOrDeviceSupported
}{
{
moduleType: "genrule",
@@ -221,14 +214,17 @@
{
moduleType: "cc_genrule",
factory: cc.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule",
factory: java.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule_host",
factory: java.GenRuleFactoryHost,
+ hod: android.HostSupported,
},
}
@@ -242,32 +238,25 @@
}`
for _, tc := range testCases {
- moduleAttrs := attrNameToString{
+ moduleAttrs := AttrNameToString{
"cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
"outs": `["foo.out"]`,
"srcs": `["foo.in"]`,
"tools": `["//other:foo.tool"]`,
}
- if tc.moduleType == "java_genrule_host" {
- moduleAttrs["target_compatible_with"] = `select({
- "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
- "//conditions:default": [],
- })`
- }
-
expectedBazelTargets := []string{
- makeBazelTarget("genrule", "foo", moduleAttrs),
+ makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
}
t.Run(tc.moduleType, func(t *testing.T) {
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
- bp2buildTestCase{
- moduleTypeUnderTest: tc.moduleType,
- moduleTypeUnderTestFactory: tc.factory,
- blueprint: fmt.Sprintf(bp, tc.moduleType),
- expectedBazelTargets: expectedBazelTargets,
- filesystem: otherGenruleBp(tc.moduleType),
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+ Bp2buildTestCase{
+ ModuleTypeUnderTest: tc.moduleType,
+ ModuleTypeUnderTestFactory: tc.factory,
+ Blueprint: fmt.Sprintf(bp, tc.moduleType),
+ ExpectedBazelTargets: expectedBazelTargets,
+ Filesystem: otherGenruleBp(tc.moduleType),
})
})
}
@@ -277,6 +266,7 @@
testCases := []struct {
moduleType string
factory android.ModuleFactory
+ hod android.HostOrDeviceSupported
}{
{
moduleType: "genrule",
@@ -285,14 +275,17 @@
{
moduleType: "cc_genrule",
factory: cc.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule",
factory: java.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule_host",
factory: java.GenRuleFactoryHost,
+ hod: android.HostSupported,
},
}
@@ -306,32 +299,25 @@
}`
for _, tc := range testCases {
- moduleAttrs := attrNameToString{
+ moduleAttrs := AttrNameToString{
"cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)"`,
"outs": `["foo.out"]`,
"srcs": `["//other:other.tool"]`,
"tools": `["//other:foo.tool"]`,
}
- if tc.moduleType == "java_genrule_host" {
- moduleAttrs["target_compatible_with"] = `select({
- "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
- "//conditions:default": [],
- })`
- }
-
expectedBazelTargets := []string{
- makeBazelTarget("genrule", "foo", moduleAttrs),
+ makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
}
t.Run(tc.moduleType, func(t *testing.T) {
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
- bp2buildTestCase{
- moduleTypeUnderTest: tc.moduleType,
- moduleTypeUnderTestFactory: tc.factory,
- blueprint: fmt.Sprintf(bp, tc.moduleType),
- expectedBazelTargets: expectedBazelTargets,
- filesystem: otherGenruleBp(tc.moduleType),
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+ Bp2buildTestCase{
+ ModuleTypeUnderTest: tc.moduleType,
+ ModuleTypeUnderTestFactory: tc.factory,
+ Blueprint: fmt.Sprintf(bp, tc.moduleType),
+ ExpectedBazelTargets: expectedBazelTargets,
+ Filesystem: otherGenruleBp(tc.moduleType),
})
})
}
@@ -341,6 +327,7 @@
testCases := []struct {
moduleType string
factory android.ModuleFactory
+ hod android.HostOrDeviceSupported
}{
{
moduleType: "genrule",
@@ -349,14 +336,17 @@
{
moduleType: "cc_genrule",
factory: cc.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule",
factory: java.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule_host",
factory: java.GenRuleFactoryHost,
+ hod: android.HostSupported,
},
}
@@ -370,7 +360,7 @@
}`
for _, tc := range testCases {
- moduleAttrs := attrNameToString{
+ moduleAttrs := AttrNameToString{
"cmd": `"$(location //other:foo.tool) -s $(OUTS) $(SRCS)"`,
"outs": `["foo.out"]`,
"srcs": `["foo.in"]`,
@@ -380,25 +370,18 @@
]`,
}
- if tc.moduleType == "java_genrule_host" {
- moduleAttrs["target_compatible_with"] = `select({
- "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
- "//conditions:default": [],
- })`
- }
-
expectedBazelTargets := []string{
- makeBazelTarget("genrule", "foo", moduleAttrs),
+ makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
}
t.Run(tc.moduleType, func(t *testing.T) {
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
- bp2buildTestCase{
- moduleTypeUnderTest: tc.moduleType,
- moduleTypeUnderTestFactory: tc.factory,
- blueprint: fmt.Sprintf(bp, tc.moduleType),
- expectedBazelTargets: expectedBazelTargets,
- filesystem: otherGenruleBp(tc.moduleType),
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+ Bp2buildTestCase{
+ ModuleTypeUnderTest: tc.moduleType,
+ ModuleTypeUnderTestFactory: tc.factory,
+ Blueprint: fmt.Sprintf(bp, tc.moduleType),
+ ExpectedBazelTargets: expectedBazelTargets,
+ Filesystem: otherGenruleBp(tc.moduleType),
})
})
}
@@ -408,6 +391,7 @@
testCases := []struct {
moduleType string
factory android.ModuleFactory
+ hod android.HostOrDeviceSupported
}{
{
moduleType: "genrule",
@@ -416,14 +400,17 @@
{
moduleType: "cc_genrule",
factory: cc.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule",
factory: java.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule_host",
factory: java.GenRuleFactoryHost,
+ hod: android.HostSupported,
},
}
@@ -437,7 +424,7 @@
}`
for _, tc := range testCases {
- moduleAttrs := attrNameToString{
+ moduleAttrs := AttrNameToString{
"cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
"outs": `["foo.out"]`,
"srcs": `["foo.in"]`,
@@ -447,25 +434,18 @@
]`,
}
- if tc.moduleType == "java_genrule_host" {
- moduleAttrs["target_compatible_with"] = `select({
- "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
- "//conditions:default": [],
- })`
- }
-
expectedBazelTargets := []string{
- makeBazelTarget("genrule", "foo", moduleAttrs),
+ makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
}
t.Run(tc.moduleType, func(t *testing.T) {
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
- bp2buildTestCase{
- moduleTypeUnderTest: tc.moduleType,
- moduleTypeUnderTestFactory: tc.factory,
- blueprint: fmt.Sprintf(bp, tc.moduleType),
- expectedBazelTargets: expectedBazelTargets,
- filesystem: otherGenruleBp(tc.moduleType),
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+ Bp2buildTestCase{
+ ModuleTypeUnderTest: tc.moduleType,
+ ModuleTypeUnderTestFactory: tc.factory,
+ Blueprint: fmt.Sprintf(bp, tc.moduleType),
+ ExpectedBazelTargets: expectedBazelTargets,
+ Filesystem: otherGenruleBp(tc.moduleType),
})
})
}
@@ -475,6 +455,7 @@
testCases := []struct {
moduleType string
factory android.ModuleFactory
+ hod android.HostOrDeviceSupported
}{
{
moduleType: "genrule",
@@ -483,14 +464,17 @@
{
moduleType: "cc_genrule",
factory: cc.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule",
factory: java.GenRuleFactory,
+ hod: android.DeviceSupported,
},
{
moduleType: "java_genrule_host",
factory: java.GenRuleFactoryHost,
+ hod: android.HostSupported,
},
}
@@ -503,40 +487,33 @@
}`
for _, tc := range testCases {
- moduleAttrs := attrNameToString{
+ moduleAttrs := AttrNameToString{
"cmd": `"cp $(SRCS) $(OUTS)"`,
"outs": `["foo.out"]`,
"srcs": `["foo.in"]`,
}
- if tc.moduleType == "java_genrule_host" {
- moduleAttrs["target_compatible_with"] = `select({
- "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
- "//conditions:default": [],
- })`
- }
-
expectedBazelTargets := []string{
- makeBazelTarget("genrule", "foo", moduleAttrs),
+ makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
}
t.Run(tc.moduleType, func(t *testing.T) {
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
- bp2buildTestCase{
- moduleTypeUnderTest: tc.moduleType,
- moduleTypeUnderTestFactory: tc.factory,
- blueprint: fmt.Sprintf(bp, tc.moduleType),
- expectedBazelTargets: expectedBazelTargets,
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+ Bp2buildTestCase{
+ ModuleTypeUnderTest: tc.moduleType,
+ ModuleTypeUnderTestFactory: tc.factory,
+ Blueprint: fmt.Sprintf(bp, tc.moduleType),
+ ExpectedBazelTargets: expectedBazelTargets,
})
})
}
}
func TestGenruleBp2BuildInlinesDefaults(t *testing.T) {
- testCases := []bp2buildTestCase{
+ testCases := []Bp2buildTestCase{
{
- description: "genrule applies properties from a genrule_defaults dependency if not specified",
- blueprint: `genrule_defaults {
+ Description: "genrule applies properties from a genrule_defaults dependency if not specified",
+ Blueprint: `genrule_defaults {
name: "gen_defaults",
cmd: "do-something $(in) $(out)",
}
@@ -548,8 +525,8 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("genrule", "gen", attrNameToString{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
"cmd": `"do-something $(SRCS) $(OUTS)"`,
"outs": `["out"]`,
"srcs": `["in1"]`,
@@ -557,8 +534,8 @@
},
},
{
- description: "genrule does merges properties from a genrule_defaults dependency, latest-first",
- blueprint: `genrule_defaults {
+ Description: "genrule does merges properties from a genrule_defaults dependency, latest-first",
+ Blueprint: `genrule_defaults {
name: "gen_defaults",
out: ["out-from-defaults"],
srcs: ["in-from-defaults"],
@@ -573,8 +550,8 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("genrule", "gen", attrNameToString{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
"cmd": `"do-something $(SRCS) $(OUTS)"`,
"outs": `[
"out-from-defaults",
@@ -588,8 +565,8 @@
},
},
{
- description: "genrule applies properties from list of genrule_defaults",
- blueprint: `genrule_defaults {
+ Description: "genrule applies properties from list of genrule_defaults",
+ Blueprint: `genrule_defaults {
name: "gen_defaults1",
cmd: "cp $(in) $(out)",
}
@@ -606,8 +583,8 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("genrule", "gen", attrNameToString{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
"cmd": `"cp $(SRCS) $(OUTS)"`,
"outs": `["out"]`,
"srcs": `["in1"]`,
@@ -615,8 +592,8 @@
},
},
{
- description: "genrule applies properties from genrule_defaults transitively",
- blueprint: `genrule_defaults {
+ Description: "genrule applies properties from genrule_defaults transitively",
+ Blueprint: `genrule_defaults {
name: "gen_defaults1",
defaults: ["gen_defaults2"],
cmd: "cmd1 $(in) $(out)", // overrides gen_defaults2's cmd property value.
@@ -643,8 +620,8 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("genrule", "gen", attrNameToString{
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
"cmd": `"cmd1 $(SRCS) $(OUTS)"`,
"outs": `[
"out-from-3",
@@ -661,7 +638,7 @@
}
for _, testCase := range testCases {
- t.Run(testCase.description, func(t *testing.T) {
+ t.Run(testCase.Description, func(t *testing.T) {
runGenruleTestCase(t, testCase)
})
}
diff --git a/bp2build/gensrcs_conversion_test.go b/bp2build/gensrcs_conversion_test.go
new file mode 100644
index 0000000..4845973
--- /dev/null
+++ b/bp2build/gensrcs_conversion_test.go
@@ -0,0 +1,80 @@
+// 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 bp2build
+
+import (
+ "android/soong/android"
+ "android/soong/genrule"
+ "testing"
+)
+
+func TestGensrcs(t *testing.T) {
+ testcases := []struct {
+ name string
+ bp string
+ expectedBazelAttrs AttrNameToString
+ }{
+ {
+ name: "gensrcs with common usage of properties",
+ bp: `
+ gensrcs {
+ name: "foo",
+ srcs: ["test/input.txt", ":external_files"],
+ tool_files: ["program.py"],
+ cmd: "$(location program.py) $(in) $(out)",
+ output_extension: "out",
+ bazel_module: { bp2build_available: true },
+ }`,
+ expectedBazelAttrs: AttrNameToString{
+ "srcs": `[
+ "test/input.txt",
+ ":external_files__BP2BUILD__MISSING__DEP",
+ ]`,
+ "tools": `["program.py"]`,
+ "output_extension": `"out"`,
+ "cmd": `"$(location program.py) $(SRC) $(OUT)"`,
+ },
+ },
+ {
+ name: "gensrcs with out_extension unset",
+ bp: `
+ gensrcs {
+ name: "foo",
+ srcs: ["input.txt"],
+ cmd: "cat $(in) > $(out)",
+ bazel_module: { bp2build_available: true },
+ }`,
+ expectedBazelAttrs: AttrNameToString{
+ "srcs": `["input.txt"]`,
+ "cmd": `"cat $(SRC) > $(OUT)"`,
+ },
+ },
+ }
+
+ for _, test := range testcases {
+ expectedBazelTargets := []string{
+ MakeBazelTargetNoRestrictions("gensrcs", "foo", test.expectedBazelAttrs),
+ }
+ t.Run(test.name, func(t *testing.T) {
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+ Bp2buildTestCase{
+ ModuleTypeUnderTest: "gensrcs",
+ ModuleTypeUnderTestFactory: genrule.GenSrcsFactory,
+ Blueprint: test.bp,
+ ExpectedBazelTargets: expectedBazelTargets,
+ })
+ })
+ }
+}
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index d7a76a8..50ea542 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -22,11 +22,11 @@
"android/soong/java"
)
-func runJavaBinaryHostTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaBinaryHostTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "java_binary_host"
- (&tc).moduleTypeUnderTestFactory = java.BinaryHostFactory
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+ (&tc).ModuleTypeUnderTest = "java_binary_host"
+ (&tc).ModuleTypeUnderTestFactory = java.BinaryHostFactory
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
ctx.RegisterModuleType("cc_library_host_shared", cc.LibraryHostSharedFactory)
ctx.RegisterModuleType("java_library", java.LibraryFactory)
}, tc)
@@ -41,10 +41,10 @@
}
func TestJavaBinaryHost(t *testing.T) {
- runJavaBinaryHostTestCase(t, bp2buildTestCase{
- description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
- filesystem: fs,
- blueprint: `java_binary_host {
+ runJavaBinaryHostTestCase(t, Bp2buildTestCase{
+ Description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
+ Filesystem: fs,
+ Blueprint: `java_binary_host {
name: "java-binary-host-1",
srcs: ["a.java", "b.java"],
exclude_srcs: ["b.java"],
@@ -54,8 +54,8 @@
bazel_module: { bp2build_available: true },
java_version: "8",
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_binary", "java-binary-host-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
"srcs": `["a.java"]`,
"main_class": `"com.android.test.MainClass"`,
"deps": `["//other:jni-lib-1"]`,
@@ -74,10 +74,10 @@
}
func TestJavaBinaryHostRuntimeDeps(t *testing.T) {
- runJavaBinaryHostTestCase(t, bp2buildTestCase{
- description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
- filesystem: fs,
- blueprint: `java_binary_host {
+ runJavaBinaryHostTestCase(t, Bp2buildTestCase{
+ Description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
+ Filesystem: fs,
+ Blueprint: `java_binary_host {
name: "java-binary-host-1",
static_libs: ["java-dep-1"],
manifest: "test.mf",
@@ -90,8 +90,8 @@
bazel_module: { bp2build_available: false },
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_binary", "java-binary-host-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
"main_class": `"com.android.test.MainClass"`,
"runtime_deps": `[":java-dep-1"]`,
"target_compatible_with": `select({
diff --git a/bp2build/java_import_conversion_test.go b/bp2build/java_import_conversion_test.go
index 0b3191c..707ecce 100644
--- a/bp2build/java_import_conversion_test.go
+++ b/bp2build/java_import_conversion_test.go
@@ -21,45 +21,45 @@
"testing"
)
-func runJavaImportTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaImportTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, registerJavaImportModuleTypes, tc)
+ RunBp2BuildTestCase(t, registerJavaImportModuleTypes, tc)
}
func registerJavaImportModuleTypes(ctx android.RegistrationContext) {
}
func TestJavaImportMinimal(t *testing.T) {
- runJavaImportTestCase(t, bp2buildTestCase{
- description: "Java import - simple example",
- moduleTypeUnderTest: "java_import",
- moduleTypeUnderTestFactory: java.ImportFactory,
- filesystem: map[string]string{
+ runJavaImportTestCase(t, Bp2buildTestCase{
+ Description: "Java import - simple example",
+ ModuleTypeUnderTest: "java_import",
+ ModuleTypeUnderTestFactory: java.ImportFactory,
+ Filesystem: map[string]string{
"import.jar": "",
},
- blueprint: `
+ Blueprint: `
java_import {
name: "example_import",
jars: ["import.jar"],
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_import", "example_import", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_import", "example_import", AttrNameToString{
"jars": `["import.jar"]`,
}),
}})
}
func TestJavaImportArchVariant(t *testing.T) {
- runJavaImportTestCase(t, bp2buildTestCase{
- description: "Java import - simple example",
- moduleTypeUnderTest: "java_import",
- moduleTypeUnderTestFactory: java.ImportFactory,
- filesystem: map[string]string{
+ runJavaImportTestCase(t, Bp2buildTestCase{
+ Description: "Java import - simple example",
+ ModuleTypeUnderTest: "java_import",
+ ModuleTypeUnderTestFactory: java.ImportFactory,
+ Filesystem: map[string]string{
"import.jar": "",
},
- blueprint: `
+ Blueprint: `
java_import {
name: "example_import",
target: {
@@ -73,8 +73,8 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_import", "example_import", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_import", "example_import", AttrNameToString{
"jars": `select({
"//build/bazel/platforms/os:android": ["android.jar"],
"//build/bazel/platforms/os:linux": ["linux.jar"],
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index e4d9cbc..7fa19d9 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -22,22 +22,22 @@
"android/soong/java"
)
-func runJavaLibraryTestCaseWithRegistrationCtxFunc(t *testing.T, tc bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
+func runJavaLibraryTestCaseWithRegistrationCtxFunc(t *testing.T, tc Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
t.Helper()
- (&tc).moduleTypeUnderTest = "java_library"
- (&tc).moduleTypeUnderTestFactory = java.LibraryFactory
- runBp2BuildTestCase(t, registrationCtxFunc, tc)
+ (&tc).ModuleTypeUnderTest = "java_library"
+ (&tc).ModuleTypeUnderTestFactory = java.LibraryFactory
+ RunBp2BuildTestCase(t, registrationCtxFunc, tc)
}
-func runJavaLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
runJavaLibraryTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {})
}
func TestJavaLibrary(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- description: "java_library with srcs, exclude_srcs and libs",
- blueprint: `java_library {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Description: "java_library with srcs, exclude_srcs and libs",
+ Blueprint: `java_library {
name: "java-lib-1",
srcs: ["a.java", "b.java"],
exclude_srcs: ["b.java"],
@@ -50,12 +50,12 @@
srcs: ["b.java"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"srcs": `["a.java"]`,
"deps": `[":java-lib-2"]`,
}),
- makeBazelTarget("java_library", "java-lib-2", attrNameToString{
+ makeBazelTarget("java_library", "java-lib-2", AttrNameToString{
"srcs": `["b.java"]`,
}),
},
@@ -63,8 +63,8 @@
}
func TestJavaLibraryConvertsStaticLibsToDepsAndExports(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- blueprint: `java_library {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Blueprint: `java_library {
name: "java-lib-1",
srcs: ["a.java"],
libs: ["java-lib-2"],
@@ -83,8 +83,8 @@
srcs: ["c.java"],
bazel_module: { bp2build_available: false },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"srcs": `["a.java"]`,
"deps": `[
":java-lib-2",
@@ -97,8 +97,8 @@
}
func TestJavaLibraryConvertsStaticLibsToExportsIfNoSrcs(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- blueprint: `java_library {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Blueprint: `java_library {
name: "java-lib-1",
static_libs: ["java-lib-2"],
bazel_module: { bp2build_available: true },
@@ -109,8 +109,8 @@
srcs: ["a.java"],
bazel_module: { bp2build_available: false },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"exports": `[":java-lib-2"]`,
}),
},
@@ -118,9 +118,9 @@
}
func TestJavaLibraryFailsToConvertLibsWithNoSrcs(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- expectedErr: fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."),
- blueprint: `java_library {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ ExpectedErr: fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."),
+ Blueprint: `java_library {
name: "java-lib-1",
libs: ["java-lib-2"],
bazel_module: { bp2build_available: true },
@@ -131,13 +131,13 @@
srcs: ["a.java"],
bazel_module: { bp2build_available: false },
}`,
- expectedBazelTargets: []string{},
+ ExpectedBazelTargets: []string{},
})
}
func TestJavaLibraryPlugins(t *testing.T) {
- runJavaLibraryTestCaseWithRegistrationCtxFunc(t, bp2buildTestCase{
- blueprint: `java_library {
+ runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
+ Blueprint: `java_library {
name: "java-lib-1",
plugins: ["java-plugin-1"],
bazel_module: { bp2build_available: true },
@@ -148,8 +148,8 @@
srcs: ["a.java"],
bazel_module: { bp2build_available: false },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"plugins": `[":java-plugin-1"]`,
}),
},
@@ -159,14 +159,14 @@
}
func TestJavaLibraryJavaVersion(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- blueprint: `java_library {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Blueprint: `java_library {
name: "java-lib-1",
srcs: ["a.java"],
java_version: "11",
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"srcs": `["a.java"]`,
"javacopts": `["-source 11 -target 11"]`,
}),
@@ -175,8 +175,8 @@
}
func TestJavaLibraryErrorproneJavacflagsEnabledManually(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- blueprint: `java_library {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Blueprint: `java_library {
name: "java-lib-1",
srcs: ["a.java"],
javacflags: ["-Xsuper-fast"],
@@ -185,8 +185,8 @@
javacflags: ["-Xep:SpeedLimit:OFF"],
},
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"javacopts": `[
"-Xsuper-fast",
"-Xep:SpeedLimit:OFF",
@@ -198,8 +198,8 @@
}
func TestJavaLibraryErrorproneJavacflagsErrorproneDisabledByDefault(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- blueprint: `java_library {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Blueprint: `java_library {
name: "java-lib-1",
srcs: ["a.java"],
javacflags: ["-Xsuper-fast"],
@@ -207,8 +207,8 @@
javacflags: ["-Xep:SpeedLimit:OFF"],
},
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"javacopts": `["-Xsuper-fast"]`,
"srcs": `["a.java"]`,
}),
@@ -217,8 +217,8 @@
}
func TestJavaLibraryErrorproneJavacflagsErrorproneDisabledManually(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- blueprint: `java_library {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Blueprint: `java_library {
name: "java-lib-1",
srcs: ["a.java"],
javacflags: ["-Xsuper-fast"],
@@ -227,8 +227,8 @@
javacflags: ["-Xep:SpeedLimit:OFF"],
},
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"javacopts": `["-Xsuper-fast"]`,
"srcs": `["a.java"]`,
}),
@@ -237,11 +237,11 @@
}
func TestJavaLibraryLogTags(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- description: "Java library - logtags creates separate dependency",
- moduleTypeUnderTest: "java_library",
- moduleTypeUnderTestFactory: java.LibraryFactory,
- blueprint: `java_library {
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Description: "Java library - logtags creates separate dependency",
+ ModuleTypeUnderTest: "java_library",
+ ModuleTypeUnderTestFactory: java.LibraryFactory,
+ Blueprint: `java_library {
name: "example_lib",
srcs: [
"a.java",
@@ -251,14 +251,14 @@
],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("event_log_tags", "example_lib_logtags", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("event_log_tags", "example_lib_logtags", AttrNameToString{
"srcs": `[
"a.logtag",
"b.logtag",
]`,
}),
- makeBazelTarget("java_library", "example_lib", attrNameToString{
+ makeBazelTarget("java_library", "example_lib", AttrNameToString{
"srcs": `[
"a.java",
"b.java",
@@ -269,18 +269,18 @@
}
func TestJavaLibraryResources(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- filesystem: map[string]string{
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Filesystem: map[string]string{
"res/a.res": "",
"res/b.res": "",
"res/dir1/b.res": "",
},
- blueprint: `java_library {
+ Blueprint: `java_library {
name: "java-lib-1",
java_resources: ["res/a.res", "res/b.res"],
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"resources": `[
"res/a.res",
"res/b.res",
@@ -291,18 +291,18 @@
}
func TestJavaLibraryResourceDirs(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- filesystem: map[string]string{
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Filesystem: map[string]string{
"res/a.res": "",
"res/b.res": "",
"res/dir1/b.res": "",
},
- blueprint: `java_library {
+ Blueprint: `java_library {
name: "java-lib-1",
java_resource_dirs: ["res"],
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"resource_strip_prefix": `"res"`,
"resources": `[
"res/a.res",
@@ -315,18 +315,18 @@
}
func TestJavaLibraryResourcesExcludeDir(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- filesystem: map[string]string{
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Filesystem: map[string]string{
"res/a.res": "",
"res/exclude/b.res": "",
},
- blueprint: `java_library {
+ Blueprint: `java_library {
name: "java-lib-1",
java_resource_dirs: ["res"],
exclude_java_resource_dirs: ["res/exclude"],
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"resource_strip_prefix": `"res"`,
"resources": `["res/a.res"]`,
}),
@@ -335,19 +335,19 @@
}
func TestJavaLibraryResourcesExcludeFile(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- filesystem: map[string]string{
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Filesystem: map[string]string{
"res/a.res": "",
"res/dir1/b.res": "",
"res/dir1/exclude.res": "",
},
- blueprint: `java_library {
+ Blueprint: `java_library {
name: "java-lib-1",
java_resource_dirs: ["res"],
exclude_java_resources: ["res/dir1/exclude.res"],
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"resource_strip_prefix": `"res"`,
"resources": `[
"res/a.res",
@@ -359,16 +359,16 @@
}
func TestJavaLibraryResourcesFailsWithMultipleDirs(t *testing.T) {
- runJavaLibraryTestCase(t, bp2buildTestCase{
- filesystem: map[string]string{
+ runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Filesystem: map[string]string{
"res/a.res": "",
"res1/a.res": "",
},
- blueprint: `java_library {
+ Blueprint: `java_library {
name: "java-lib-1",
java_resource_dirs: ["res", "res1"],
}`,
- expectedErr: fmt.Errorf("bp2build does not support more than one directory in java_resource_dirs (b/226423379)"),
- expectedBazelTargets: []string{},
+ ExpectedErr: fmt.Errorf("bp2build does not support more than one directory in java_resource_dirs (b/226423379)"),
+ ExpectedBazelTargets: []string{},
})
}
diff --git a/bp2build/java_library_host_conversion_test.go b/bp2build/java_library_host_conversion_test.go
index 83cc551..1dcf163 100644
--- a/bp2build/java_library_host_conversion_test.go
+++ b/bp2build/java_library_host_conversion_test.go
@@ -21,17 +21,17 @@
"android/soong/java"
)
-func runJavaLibraryHostTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaLibraryHostTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "java_library_host"
- (&tc).moduleTypeUnderTestFactory = java.LibraryHostFactory
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+ (&tc).ModuleTypeUnderTest = "java_library_host"
+ (&tc).ModuleTypeUnderTestFactory = java.LibraryHostFactory
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
}
func TestJavaLibraryHost(t *testing.T) {
- runJavaLibraryHostTestCase(t, bp2buildTestCase{
- description: "java_library_host with srcs, exclude_srcs and libs",
- blueprint: `java_library_host {
+ runJavaLibraryHostTestCase(t, Bp2buildTestCase{
+ Description: "java_library_host with srcs, exclude_srcs and libs",
+ Blueprint: `java_library_host {
name: "java-lib-host-1",
srcs: ["a.java", "b.java"],
exclude_srcs: ["b.java"],
@@ -45,8 +45,8 @@
bazel_module: { bp2build_available: true },
java_version: "9",
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_library", "java-lib-host-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-host-1", AttrNameToString{
"srcs": `["a.java"]`,
"deps": `[":java-lib-host-2"]`,
"target_compatible_with": `select({
@@ -54,7 +54,7 @@
"//conditions:default": [],
})`,
}),
- makeBazelTarget("java_library", "java-lib-host-2", attrNameToString{
+ makeBazelTarget("java_library", "java-lib-host-2", AttrNameToString{
"javacopts": `["-source 1.9 -target 1.9"]`,
"srcs": `["c.java"]`,
"target_compatible_with": `select({
diff --git a/bp2build/java_plugin_conversion_test.go b/bp2build/java_plugin_conversion_test.go
index dc763e7..2d2e5ff 100644
--- a/bp2build/java_plugin_conversion_test.go
+++ b/bp2build/java_plugin_conversion_test.go
@@ -21,19 +21,19 @@
"android/soong/java"
)
-func runJavaPluginTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaPluginTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "java_plugin"
- (&tc).moduleTypeUnderTestFactory = java.PluginFactory
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+ (&tc).ModuleTypeUnderTest = "java_plugin"
+ (&tc).ModuleTypeUnderTestFactory = java.PluginFactory
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
ctx.RegisterModuleType("java_library", java.LibraryFactory)
}, tc)
}
func TestJavaPlugin(t *testing.T) {
- runJavaPluginTestCase(t, bp2buildTestCase{
- description: "java_plugin with srcs, libs, static_libs",
- blueprint: `java_plugin {
+ runJavaPluginTestCase(t, Bp2buildTestCase{
+ Description: "java_plugin with srcs, libs, static_libs",
+ Blueprint: `java_plugin {
name: "java-plug-1",
srcs: ["a.java", "b.java"],
libs: ["java-lib-1"],
@@ -53,8 +53,8 @@
srcs: ["c.java"],
bazel_module: { bp2build_available: false },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_plugin", "java-plug-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_plugin", "java-plug-1", AttrNameToString{
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
@@ -74,9 +74,9 @@
}
func TestJavaPluginNoSrcs(t *testing.T) {
- runJavaPluginTestCase(t, bp2buildTestCase{
- description: "java_plugin without srcs converts (static) libs to deps",
- blueprint: `java_plugin {
+ runJavaPluginTestCase(t, Bp2buildTestCase{
+ Description: "java_plugin without srcs converts (static) libs to deps",
+ Blueprint: `java_plugin {
name: "java-plug-1",
libs: ["java-lib-1"],
static_libs: ["java-lib-2"],
@@ -94,8 +94,8 @@
srcs: ["c.java"],
bazel_module: { bp2build_available: false },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("java_plugin", "java-plug-1", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("java_plugin", "java-plug-1", AttrNameToString{
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go
index c6feeb8..6465641 100644
--- a/bp2build/java_proto_conversion_test.go
+++ b/bp2build/java_proto_conversion_test.go
@@ -22,11 +22,11 @@
"android/soong/java"
)
-func runJavaProtoTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaProtoTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "java_library_static"
- (&tc).moduleTypeUnderTestFactory = java.LibraryFactory
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+ (&tc).ModuleTypeUnderTest = "java_library_static"
+ (&tc).ModuleTypeUnderTestFactory = java.LibraryFactory
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
}
func TestJavaProto(t *testing.T) {
@@ -70,25 +70,25 @@
srcs: ["a.proto"],
}`
- protoLibrary := makeBazelTarget("proto_library", "java-protos_proto", attrNameToString{
+ protoLibrary := makeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{
"srcs": `["a.proto"]`,
})
for _, tc := range testCases {
javaLibraryName := fmt.Sprintf("java-protos_%s", tc.javaLibraryNameExtension)
- runJavaProtoTestCase(t, bp2buildTestCase{
- description: fmt.Sprintf("java_proto %s", tc.protoType),
- blueprint: fmt.Sprintf(bp, tc.protoType),
- expectedBazelTargets: []string{
+ runJavaProtoTestCase(t, Bp2buildTestCase{
+ Description: fmt.Sprintf("java_proto %s", tc.protoType),
+ Blueprint: fmt.Sprintf(bp, tc.protoType),
+ ExpectedBazelTargets: []string{
protoLibrary,
makeBazelTarget(
tc.javaLibraryType,
javaLibraryName,
- attrNameToString{
+ AttrNameToString{
"deps": `[":java-protos_proto"]`,
}),
- makeBazelTarget("java_library", "java-protos", attrNameToString{
+ makeBazelTarget("java_library", "java-protos", AttrNameToString{
"exports": fmt.Sprintf(`[":%s"]`, javaLibraryName),
}),
},
@@ -97,25 +97,25 @@
}
func TestJavaProtoDefault(t *testing.T) {
- runJavaProtoTestCase(t, bp2buildTestCase{
- description: "java_library proto default",
- blueprint: `java_library_static {
+ runJavaProtoTestCase(t, Bp2buildTestCase{
+ Description: "java_library proto default",
+ Blueprint: `java_library_static {
name: "java-protos",
srcs: ["a.proto"],
java_version: "7",
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("proto_library", "java-protos_proto", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{
"srcs": `["a.proto"]`,
}),
makeBazelTarget(
"java_lite_proto_library",
"java-protos_java_proto_lite",
- attrNameToString{
+ AttrNameToString{
"deps": `[":java-protos_proto"]`,
}),
- makeBazelTarget("java_library", "java-protos", attrNameToString{
+ makeBazelTarget("java_library", "java-protos", AttrNameToString{
"exports": `[":java-protos_java_proto_lite"]`,
"javacopts": `["-source 1.7 -target 1.7"]`,
}),
diff --git a/bp2build/linker_config_conversion_test.go b/bp2build/linker_config_conversion_test.go
new file mode 100644
index 0000000..3b8a363
--- /dev/null
+++ b/bp2build/linker_config_conversion_test.go
@@ -0,0 +1,59 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+ "fmt"
+ "testing"
+
+ "android/soong/linkerconfig"
+)
+
+func runLinkerConfigTestCase(t *testing.T, tc Bp2buildTestCase) {
+ t.Helper()
+ (&tc).ModuleTypeUnderTest = "linker_config"
+ (&tc).ModuleTypeUnderTestFactory = linkerconfig.LinkerConfigFactory
+ runBp2BuildTestCaseSimple(t, tc)
+}
+
+func TestLinkerConfigConvertsSrc(t *testing.T) {
+ runLinkerConfigTestCase(t,
+ Bp2buildTestCase{
+ Blueprint: `
+linker_config {
+ name: "foo",
+ src: "a.json",
+}
+`,
+ ExpectedBazelTargets: []string{makeBazelTarget("linker_config", "foo", AttrNameToString{
+ "src": `"a.json"`,
+ })},
+ })
+
+}
+
+func TestLinkerConfigNoSrc(t *testing.T) {
+ runLinkerConfigTestCase(t,
+ Bp2buildTestCase{
+ Blueprint: `
+linker_config {
+ name: "foo",
+}
+`,
+ ExpectedBazelTargets: []string{},
+ ExpectedErr: fmt.Errorf("Android.bp:2:1: module \"foo\": src: empty src is not supported"),
+ })
+
+}
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index 04fac44..3a21c34 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -116,8 +116,6 @@
}
if _, err := os.Stat(metricsFile); err != nil {
fail(err, "MISSING BP2BUILD METRICS OUTPUT: Failed to `stat` %s", metricsFile)
- } else {
- fmt.Printf("\nWrote bp2build metrics to: %s\n", metricsFile)
}
}
diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
index 2e4b221..fce4c74 100644
--- a/bp2build/prebuilt_etc_conversion_test.go
+++ b/bp2build/prebuilt_etc_conversion_test.go
@@ -21,21 +21,21 @@
"testing"
)
-func runPrebuiltEtcTestCase(t *testing.T, tc bp2buildTestCase) {
+func runPrebuiltEtcTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "prebuilt_etc"
- (&tc).moduleTypeUnderTestFactory = etc.PrebuiltEtcFactory
- runBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
+ (&tc).ModuleTypeUnderTest = "prebuilt_etc"
+ (&tc).ModuleTypeUnderTestFactory = etc.PrebuiltEtcFactory
+ RunBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
}
func registerPrebuiltEtcModuleTypes(ctx android.RegistrationContext) {
}
func TestPrebuiltEtcSimple(t *testing.T) {
- runPrebuiltEtcTestCase(t, bp2buildTestCase{
- description: "prebuilt_etc - simple example",
- filesystem: map[string]string{},
- blueprint: `
+ runPrebuiltEtcTestCase(t, Bp2buildTestCase{
+ Description: "prebuilt_etc - simple example",
+ Filesystem: map[string]string{},
+ Blueprint: `
prebuilt_etc {
name: "apex_tz_version",
src: "version/tz_version",
@@ -44,8 +44,8 @@
installable: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_file", "apex_tz_version", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
"filename": `"tz_version"`,
"installable": `False`,
"src": `"version/tz_version"`,
@@ -54,10 +54,10 @@
}
func TestPrebuiltEtcArchVariant(t *testing.T) {
- runPrebuiltEtcTestCase(t, bp2buildTestCase{
- description: "prebuilt_etc - arch variant",
- filesystem: map[string]string{},
- blueprint: `
+ runPrebuiltEtcTestCase(t, Bp2buildTestCase{
+ Description: "prebuilt_etc - arch variant",
+ Filesystem: map[string]string{},
+ Blueprint: `
prebuilt_etc {
name: "apex_tz_version",
src: "version/tz_version",
@@ -74,8 +74,8 @@
}
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_file", "apex_tz_version", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
"filename": `"tz_version"`,
"installable": `False`,
"src": `select({
@@ -88,10 +88,10 @@
}
func TestPrebuiltEtcArchAndTargetVariant(t *testing.T) {
- runPrebuiltEtcTestCase(t, bp2buildTestCase{
- description: "prebuilt_etc - arch variant",
- filesystem: map[string]string{},
- blueprint: `
+ runPrebuiltEtcTestCase(t, Bp2buildTestCase{
+ Description: "prebuilt_etc - arch variant",
+ Filesystem: map[string]string{},
+ Blueprint: `
prebuilt_etc {
name: "apex_tz_version",
src: "version/tz_version",
@@ -113,8 +113,8 @@
},
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_file", "apex_tz_version", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
"filename": `"tz_version"`,
"installable": `False`,
"src": `select({
@@ -129,21 +129,21 @@
})}})
}
-func runPrebuiltUsrShareTestCase(t *testing.T, tc bp2buildTestCase) {
+func runPrebuiltUsrShareTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- (&tc).moduleTypeUnderTest = "prebuilt_usr_share"
- (&tc).moduleTypeUnderTestFactory = etc.PrebuiltUserShareFactory
- runBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
+ (&tc).ModuleTypeUnderTest = "prebuilt_usr_share"
+ (&tc).ModuleTypeUnderTestFactory = etc.PrebuiltUserShareFactory
+ RunBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
}
func registerPrebuiltUsrShareModuleTypes(ctx android.RegistrationContext) {
}
func TestPrebuiltUsrShareSimple(t *testing.T) {
- runPrebuiltUsrShareTestCase(t, bp2buildTestCase{
- description: "prebuilt_usr_share - simple example",
- filesystem: map[string]string{},
- blueprint: `
+ runPrebuiltUsrShareTestCase(t, Bp2buildTestCase{
+ Description: "prebuilt_usr_share - simple example",
+ Filesystem: map[string]string{},
+ Blueprint: `
prebuilt_usr_share {
name: "apex_tz_version",
src: "version/tz_version",
@@ -152,8 +152,8 @@
installable: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_file", "apex_tz_version", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
"filename": `"tz_version"`,
"installable": `False`,
"src": `"version/tz_version"`,
@@ -162,10 +162,10 @@
}
func TestPrebuiltEtcNoSubdir(t *testing.T) {
- runPrebuiltEtcTestCase(t, bp2buildTestCase{
- description: "prebuilt_etc - no subdir",
- filesystem: map[string]string{},
- blueprint: `
+ runPrebuiltEtcTestCase(t, Bp2buildTestCase{
+ Description: "prebuilt_etc - no subdir",
+ Filesystem: map[string]string{},
+ Blueprint: `
prebuilt_etc {
name: "apex_tz_version",
src: "version/tz_version",
@@ -173,8 +173,8 @@
installable: false,
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("prebuilt_file", "apex_tz_version", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
"filename": `"tz_version"`,
"installable": `False`,
"src": `"version/tz_version"`,
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index dfa11d1..79da5d5 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -7,27 +7,27 @@
"android/soong/python"
)
-func runBp2BuildTestCaseWithPythonLibraries(t *testing.T, tc bp2buildTestCase) {
+func runBp2BuildTestCaseWithPythonLibraries(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
ctx.RegisterModuleType("python_library_host", python.PythonLibraryHostFactory)
}, tc)
}
func TestPythonBinaryHostSimple(t *testing.T) {
- runBp2BuildTestCaseWithPythonLibraries(t, bp2buildTestCase{
- description: "simple python_binary_host converts to a native py_binary",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- filesystem: map[string]string{
+ runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
+ Description: "simple python_binary_host converts to a native py_binary",
+ ModuleTypeUnderTest: "python_binary_host",
+ ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ Filesystem: map[string]string{
"a.py": "",
"b/c.py": "",
"b/d.py": "",
"b/e.py": "",
"files/data.txt": "",
},
- blueprint: `python_binary_host {
+ Blueprint: `python_binary_host {
name: "foo",
main: "a.py",
srcs: ["**/*.py"],
@@ -41,11 +41,12 @@
srcs: ["b/e.py"],
bazel_module: { bp2build_available: false },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("py_binary", "foo", attrNameToString{
- "data": `["files/data.txt"]`,
- "deps": `[":bar"]`,
- "main": `"a.py"`,
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("py_binary", "foo", AttrNameToString{
+ "data": `["files/data.txt"]`,
+ "deps": `[":bar"]`,
+ "main": `"a.py"`,
+ "imports": `["."]`,
"srcs": `[
"a.py",
"b/c.py",
@@ -61,11 +62,11 @@
}
func TestPythonBinaryHostPy2(t *testing.T) {
- runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: "py2 python_binary_host",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- blueprint: `python_binary_host {
+ runBp2BuildTestCaseSimple(t, Bp2buildTestCase{
+ Description: "py2 python_binary_host",
+ ModuleTypeUnderTest: "python_binary_host",
+ ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ Blueprint: `python_binary_host {
name: "foo",
srcs: ["a.py"],
version: {
@@ -80,9 +81,10 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{
- makeBazelTarget("py_binary", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("py_binary", "foo", AttrNameToString{
"python_version": `"PY2"`,
+ "imports": `["."]`,
"srcs": `["a.py"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
@@ -94,11 +96,11 @@
}
func TestPythonBinaryHostPy3(t *testing.T) {
- runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: "py3 python_binary_host",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- blueprint: `python_binary_host {
+ runBp2BuildTestCaseSimple(t, Bp2buildTestCase{
+ Description: "py3 python_binary_host",
+ ModuleTypeUnderTest: "python_binary_host",
+ ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ Blueprint: `python_binary_host {
name: "foo",
srcs: ["a.py"],
version: {
@@ -113,10 +115,11 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{
+ ExpectedBazelTargets: []string{
// python_version is PY3 by default.
- makeBazelTarget("py_binary", "foo", attrNameToString{
- "srcs": `["a.py"]`,
+ makeBazelTarget("py_binary", "foo", AttrNameToString{
+ "imports": `["."]`,
+ "srcs": `["a.py"]`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
@@ -127,15 +130,15 @@
}
func TestPythonBinaryHostArchVariance(t *testing.T) {
- runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: "test arch variants",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- filesystem: map[string]string{
+ runBp2BuildTestCaseSimple(t, Bp2buildTestCase{
+ Description: "test arch variants",
+ ModuleTypeUnderTest: "python_binary_host",
+ ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ Filesystem: map[string]string{
"dir/arm.py": "",
"dir/x86.py": "",
},
- blueprint: `python_binary_host {
+ Blueprint: `python_binary_host {
name: "foo-arm",
arch: {
arm: {
@@ -146,8 +149,9 @@
},
},
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("py_binary", "foo-arm", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("py_binary", "foo-arm", AttrNameToString{
+ "imports": `["."]`,
"srcs": `select({
"//build/bazel/platforms/arch:arm": ["arm.py"],
"//build/bazel/platforms/arch:x86": ["x86.py"],
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
index 66c2290..1d6061b 100644
--- a/bp2build/python_library_conversion_test.go
+++ b/bp2build/python_library_conversion_test.go
@@ -21,7 +21,7 @@
expectedError error
}
-func convertPythonLibTestCaseToBp2build_Host(tc pythonLibBp2BuildTestCase) bp2buildTestCase {
+func convertPythonLibTestCaseToBp2build_Host(tc pythonLibBp2BuildTestCase) Bp2buildTestCase {
for i := range tc.expectedBazelTargets {
tc.expectedBazelTargets[i].attrs["target_compatible_with"] = `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
@@ -32,7 +32,7 @@
return convertPythonLibTestCaseToBp2build(tc)
}
-func convertPythonLibTestCaseToBp2build(tc pythonLibBp2BuildTestCase) bp2buildTestCase {
+func convertPythonLibTestCaseToBp2build(tc pythonLibBp2BuildTestCase) Bp2buildTestCase {
var bp2BuildTargets []string
for _, t := range tc.expectedBazelTargets {
bp2BuildTargets = append(bp2BuildTargets, makeBazelTarget(t.typ, t.name, t.attrs))
@@ -43,28 +43,28 @@
for k, v := range tc.filesystem {
filesystemCopy[k] = v
}
- return bp2buildTestCase{
- description: tc.description,
- filesystem: filesystemCopy,
- blueprint: tc.blueprint,
- expectedBazelTargets: bp2BuildTargets,
- dir: tc.dir,
- expectedErr: tc.expectedError,
+ return Bp2buildTestCase{
+ Description: tc.description,
+ Filesystem: filesystemCopy,
+ Blueprint: tc.blueprint,
+ ExpectedBazelTargets: bp2BuildTargets,
+ Dir: tc.dir,
+ ExpectedErr: tc.expectedError,
}
}
func runPythonLibraryTestCase(t *testing.T, tc pythonLibBp2BuildTestCase) {
t.Helper()
testCase := convertPythonLibTestCaseToBp2build(tc)
- testCase.description = fmt.Sprintf(testCase.description, "python_library")
- testCase.blueprint = fmt.Sprintf(testCase.blueprint, "python_library")
- for name, contents := range testCase.filesystem {
+ testCase.Description = fmt.Sprintf(testCase.Description, "python_library")
+ testCase.Blueprint = fmt.Sprintf(testCase.Blueprint, "python_library")
+ for name, contents := range testCase.Filesystem {
if strings.HasSuffix(name, "Android.bp") {
- testCase.filesystem[name] = fmt.Sprintf(contents, "python_library")
+ testCase.Filesystem[name] = fmt.Sprintf(contents, "python_library")
}
}
- testCase.moduleTypeUnderTest = "python_library"
- testCase.moduleTypeUnderTestFactory = python.PythonLibraryFactory
+ testCase.ModuleTypeUnderTest = "python_library"
+ testCase.ModuleTypeUnderTestFactory = python.PythonLibraryFactory
runBp2BuildTestCaseSimple(t, testCase)
}
@@ -72,16 +72,16 @@
func runPythonLibraryHostTestCase(t *testing.T, tc pythonLibBp2BuildTestCase) {
t.Helper()
testCase := convertPythonLibTestCaseToBp2build_Host(tc)
- testCase.description = fmt.Sprintf(testCase.description, "python_library_host")
- testCase.blueprint = fmt.Sprintf(testCase.blueprint, "python_library_host")
- for name, contents := range testCase.filesystem {
+ testCase.Description = fmt.Sprintf(testCase.Description, "python_library_host")
+ testCase.Blueprint = fmt.Sprintf(testCase.Blueprint, "python_library_host")
+ for name, contents := range testCase.Filesystem {
if strings.HasSuffix(name, "Android.bp") {
- testCase.filesystem[name] = fmt.Sprintf(contents, "python_library_host")
+ testCase.Filesystem[name] = fmt.Sprintf(contents, "python_library_host")
}
}
- testCase.moduleTypeUnderTest = "python_library_host"
- testCase.moduleTypeUnderTestFactory = python.PythonLibraryHostFactory
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+ testCase.ModuleTypeUnderTest = "python_library_host"
+ testCase.ModuleTypeUnderTestFactory = python.PythonLibraryHostFactory
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
},
testCase)
@@ -121,7 +121,7 @@
{
typ: "py_library",
name: "foo",
- attrs: attrNameToString{
+ attrs: AttrNameToString{
"data": `["files/data.txt"]`,
"deps": `[":bar"]`,
"srcs": `[
@@ -155,7 +155,7 @@
{
typ: "py_library",
name: "foo",
- attrs: attrNameToString{
+ attrs: AttrNameToString{
"srcs": `["a.py"]`,
"srcs_version": `"PY2"`,
"imports": `["."]`,
@@ -183,7 +183,7 @@
{
typ: "py_library",
name: "foo",
- attrs: attrNameToString{
+ attrs: AttrNameToString{
"srcs": `["a.py"]`,
"srcs_version": `"PY3"`,
"imports": `["."]`,
@@ -212,7 +212,7 @@
// srcs_version is PY2ANDPY3 by default.
typ: "py_library",
name: "foo",
- attrs: attrNameToString{
+ attrs: AttrNameToString{
"srcs": `["a.py"]`,
"imports": `["."]`,
},
@@ -238,7 +238,7 @@
// srcs_version is PY2ANDPY3 by default.
typ: "py_library",
name: "foo",
- attrs: attrNameToString{
+ attrs: AttrNameToString{
"srcs": `["a.py"]`,
"imports": `["../.."]`,
"srcs_version": `"PY3"`,
@@ -292,7 +292,7 @@
{
typ: "py_library",
name: "foo",
- attrs: attrNameToString{
+ attrs: AttrNameToString{
"srcs": `select({
"//build/bazel/platforms/arch:arm": ["arm.py"],
"//build/bazel/platforms/arch:x86": ["x86.py"],
@@ -305,3 +305,46 @@
},
})
}
+
+func TestPythonLibraryWithProtobufs(t *testing.T) {
+ runPythonLibraryTestCases(t, pythonLibBp2BuildTestCase{
+ description: "test %s protobuf",
+ filesystem: map[string]string{
+ "dir/mylib.py": "",
+ "dir/myproto.proto": "",
+ },
+ blueprint: `%s {
+ name: "foo",
+ srcs: [
+ "dir/mylib.py",
+ "dir/myproto.proto",
+ ],
+ }`,
+ expectedBazelTargets: []testBazelTarget{
+ {
+ typ: "proto_library",
+ name: "foo_proto",
+ attrs: AttrNameToString{
+ "srcs": `["dir/myproto.proto"]`,
+ },
+ },
+ {
+ typ: "py_proto_library",
+ name: "foo_py_proto",
+ attrs: AttrNameToString{
+ "deps": `[":foo_proto"]`,
+ },
+ },
+ {
+ typ: "py_library",
+ name: "foo",
+ attrs: AttrNameToString{
+ "srcs": `["dir/mylib.py"]`,
+ "srcs_version": `"PY3"`,
+ "imports": `["."]`,
+ "deps": `[":foo_py_proto"]`,
+ },
+ },
+ },
+ })
+}
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index ac89087..d8f701d 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -48,25 +48,25 @@
}
}
-func runShBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
+func runShBinaryTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
}
func TestShBinarySimple(t *testing.T) {
- runShBinaryTestCase(t, bp2buildTestCase{
- description: "sh_binary test",
- moduleTypeUnderTest: "sh_binary",
- moduleTypeUnderTestFactory: sh.ShBinaryFactory,
- blueprint: `sh_binary {
+ runShBinaryTestCase(t, Bp2buildTestCase{
+ Description: "sh_binary test",
+ ModuleTypeUnderTest: "sh_binary",
+ ModuleTypeUnderTestFactory: sh.ShBinaryFactory,
+ Blueprint: `sh_binary {
name: "foo",
src: "foo.sh",
filename: "foo.exe",
sub_dir: "sub",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("sh_binary", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("sh_binary", "foo", AttrNameToString{
"srcs": `["foo.sh"]`,
"filename": `"foo.exe"`,
"sub_dir": `"sub"`,
@@ -75,17 +75,17 @@
}
func TestShBinaryDefaults(t *testing.T) {
- runShBinaryTestCase(t, bp2buildTestCase{
- description: "sh_binary test",
- moduleTypeUnderTest: "sh_binary",
- moduleTypeUnderTestFactory: sh.ShBinaryFactory,
- blueprint: `sh_binary {
+ runShBinaryTestCase(t, Bp2buildTestCase{
+ Description: "sh_binary test",
+ ModuleTypeUnderTest: "sh_binary",
+ ModuleTypeUnderTestFactory: sh.ShBinaryFactory,
+ Blueprint: `sh_binary {
name: "foo",
src: "foo.sh",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{
- makeBazelTarget("sh_binary", "foo", attrNameToString{
+ ExpectedBazelTargets: []string{
+ makeBazelTarget("sh_binary", "foo", AttrNameToString{
"srcs": `["foo.sh"]`,
})},
})
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index b1e1fb2..a94b2b9 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -20,9 +20,9 @@
"testing"
)
-func runSoongConfigModuleTypeTest(t *testing.T, tc bp2buildTestCase) {
+func runSoongConfigModuleTypeTest(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, registerSoongConfigModuleTypes, tc)
+ RunBp2BuildTestCase(t, registerSoongConfigModuleTypes, tc)
}
func registerSoongConfigModuleTypes(ctx android.RegistrationContext) {
@@ -49,6 +49,7 @@
custom_cc_library_static {
name: "foo",
bazel_module: { bp2build_available: true },
+ host_supported: true,
soong_config_variables: {
feature1: {
conditions_default: {
@@ -60,12 +61,12 @@
}
`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - soong_config_module_type is supported in bp2build",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- blueprint: bp,
- expectedBazelTargets: []string{`cc_library_static(
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - soong_config_module_type is supported in bp2build",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Blueprint: bp,
+ ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
"//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
@@ -94,6 +95,7 @@
custom_cc_library_static {
name: "foo",
bazel_module: { bp2build_available: true },
+ host_supported: true,
soong_config_variables: {
feature1: {
conditions_default: {
@@ -105,15 +107,15 @@
}
`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - soong_config_module_type_import is supported in bp2build",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- filesystem: map[string]string{
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - soong_config_module_type_import is supported in bp2build",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Filesystem: map[string]string{
"foo/bar/SoongConfig.bp": configBp,
},
- blueprint: bp,
- expectedBazelTargets: []string{`cc_library_static(
+ Blueprint: bp,
+ ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
"//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
@@ -141,6 +143,7 @@
custom_cc_library_static {
name: "foo",
bazel_module: { bp2build_available: true },
+ host_supported: true,
soong_config_variables: {
board: {
soc_a: {
@@ -158,12 +161,12 @@
}
`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - generates selects for string vars",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- blueprint: bp,
- expectedBazelTargets: []string{`cc_library_static(
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for string vars",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Blueprint: bp,
+ ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
"//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
@@ -200,6 +203,7 @@
custom_cc_library_static {
name: "foo",
bazel_module: { bp2build_available: true },
+ host_supported: true,
soong_config_variables: {
feature1: {
conditions_default: {
@@ -228,12 +232,12 @@
},
}`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - generates selects for multiple variable types",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- blueprint: bp,
- expectedBazelTargets: []string{`cc_library_static(
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for multiple variable types",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Blueprint: bp,
+ ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
"//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
@@ -268,6 +272,7 @@
custom_cc_library_static {
name: "foo",
bazel_module: { bp2build_available: true },
+ host_supported: true,
soong_config_variables: {
board: {
soc_a: {
@@ -293,15 +298,15 @@
cc_library_static { name: "soc_default_static_dep", bazel_module: { bp2build_available: false } }
`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - generates selects for label list attributes",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- blueprint: bp,
- filesystem: map[string]string{
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for label list attributes",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Blueprint: bp,
+ Filesystem: map[string]string{
"foo/bar/Android.bp": otherDeps,
},
- expectedBazelTargets: []string{`cc_library_static(
+ ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
"//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
@@ -356,15 +361,16 @@
name: "lib",
defaults: ["foo_defaults_2"],
bazel_module: { bp2build_available: true },
+ host_supported: true,
}
`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - defaults with a single namespace",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- blueprint: bp,
- expectedBazelTargets: []string{`cc_library_static(
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - defaults with a single namespace",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Blueprint: bp,
+ ExpectedBazelTargets: []string{`cc_library_static(
name = "lib",
copts = select({
"//build/bazel/product_variables:vendor_foo__feature": [
@@ -429,21 +435,23 @@
name: "lib",
defaults: ["foo_defaults", "bar_defaults"],
bazel_module: { bp2build_available: true },
+ host_supported: true,
}
cc_library_static {
name: "lib2",
defaults: ["bar_defaults", "foo_defaults"],
bazel_module: { bp2build_available: true },
+ host_supported: true,
}
`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - multiple defaults with a single namespace",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- blueprint: bp,
- expectedBazelTargets: []string{`cc_library_static(
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - multiple defaults with a single namespace",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Blueprint: bp,
+ ExpectedBazelTargets: []string{`cc_library_static(
name = "lib",
asflags = select({
"//build/bazel/product_variables:acme__feature": ["-asflag_bar"],
@@ -550,15 +558,16 @@
name: "lib",
defaults: ["foo_defaults", "qux_defaults"],
bazel_module: { bp2build_available: true },
+ host_supported: true,
}
`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - defaults with multiple namespaces",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- blueprint: bp,
- expectedBazelTargets: []string{`cc_library_static(
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - defaults with multiple namespaces",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Blueprint: bp,
+ ExpectedBazelTargets: []string{`cc_library_static(
name = "lib",
copts = select({
"//build/bazel/product_variables:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"],
@@ -615,6 +624,7 @@
library_linking_strategy_cc_defaults {
name: "library_linking_strategy_merged_defaults",
defaults: ["library_linking_strategy_lib_a_defaults"],
+ host_supported: true,
soong_config_variables: {
library_linking_strategy: {
prefer_static: {
@@ -643,15 +653,15 @@
cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - generates selects for library_linking_strategy",
- moduleTypeUnderTest: "cc_binary",
- moduleTypeUnderTestFactory: cc.BinaryFactory,
- blueprint: bp,
- filesystem: map[string]string{
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for library_linking_strategy",
+ ModuleTypeUnderTest: "cc_binary",
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Blueprint: bp,
+ Filesystem: map[string]string{
"foo/bar/Android.bp": otherDeps,
},
- expectedBazelTargets: []string{`cc_binary(
+ ExpectedBazelTargets: []string{`cc_binary(
name = "library_linking_strategy_sample_binary",
deps = select({
"//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
@@ -714,6 +724,7 @@
cc_binary {
name: "library_linking_strategy_sample_binary",
+ host_supported: true,
srcs: ["library_linking_strategy.cc"],
defaults: ["library_linking_strategy_sample_defaults"],
}`
@@ -723,15 +734,15 @@
cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - generates selects for library_linking_strategy",
- moduleTypeUnderTest: "cc_binary",
- moduleTypeUnderTestFactory: cc.BinaryFactory,
- blueprint: bp,
- filesystem: map[string]string{
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for library_linking_strategy",
+ ModuleTypeUnderTest: "cc_binary",
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Blueprint: bp,
+ Filesystem: map[string]string{
"foo/bar/Android.bp": otherDeps,
},
- expectedBazelTargets: []string{`cc_binary(
+ ExpectedBazelTargets: []string{`cc_binary(
name = "library_linking_strategy_sample_binary",
deps = select({
"//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
@@ -800,6 +811,7 @@
cc_binary {
name: "alphabet_binary",
+ host_supported: true,
srcs: ["main.cc"],
defaults: ["alphabet_sample_cc_defaults"],
}`
@@ -810,15 +822,15 @@
cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - generates selects for library_linking_strategy",
- moduleTypeUnderTest: "cc_binary",
- moduleTypeUnderTestFactory: cc.BinaryFactory,
- blueprint: bp,
- filesystem: map[string]string{
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for library_linking_strategy",
+ ModuleTypeUnderTest: "cc_binary",
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Blueprint: bp,
+ Filesystem: map[string]string{
"foo/bar/Android.bp": otherDeps,
},
- expectedBazelTargets: []string{`cc_binary(
+ ExpectedBazelTargets: []string{`cc_binary(
name = "alphabet_binary",
deps = select({
"//build/bazel/product_variables:android__alphabet__a": [],
@@ -861,6 +873,7 @@
cc_binary {
name: "alphabet_binary",
srcs: ["main.cc"],
+ host_supported: true,
defaults: ["alphabet_sample_cc_defaults"],
enabled: false,
arch: {
@@ -875,13 +888,13 @@
},
}`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - generates selects for library_linking_strategy",
- moduleTypeUnderTest: "cc_binary",
- moduleTypeUnderTestFactory: cc.BinaryFactory,
- blueprint: bp,
- filesystem: map[string]string{},
- expectedBazelTargets: []string{`cc_binary(
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for library_linking_strategy",
+ ModuleTypeUnderTest: "cc_binary",
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Blueprint: bp,
+ Filesystem: map[string]string{},
+ ExpectedBazelTargets: []string{`cc_binary(
name = "alphabet_binary",
local_includes = ["."],
srcs = ["main.cc"],
@@ -928,13 +941,13 @@
enabled: false,
}`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - generates selects for library_linking_strategy",
- moduleTypeUnderTest: "cc_binary",
- moduleTypeUnderTestFactory: cc.BinaryFactory,
- blueprint: bp,
- filesystem: map[string]string{},
- expectedBazelTargets: []string{`cc_binary(
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for library_linking_strategy",
+ ModuleTypeUnderTest: "cc_binary",
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Blueprint: bp,
+ Filesystem: map[string]string{},
+ ExpectedBazelTargets: []string{`cc_binary(
name = "alphabet_binary",
local_includes = ["."],
srcs = ["main.cc"],
@@ -958,6 +971,7 @@
alphabet_cc_defaults {
name: "alphabet_sample_cc_defaults",
+ host_supported: true,
soong_config_variables: {
special_build: {
enabled: true,
@@ -971,13 +985,13 @@
defaults: ["alphabet_sample_cc_defaults"],
}`
- runSoongConfigModuleTypeTest(t, bp2buildTestCase{
- description: "soong config variables - generates selects for library_linking_strategy",
- moduleTypeUnderTest: "cc_binary",
- moduleTypeUnderTestFactory: cc.BinaryFactory,
- blueprint: bp,
- filesystem: map[string]string{},
- expectedBazelTargets: []string{`cc_binary(
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for library_linking_strategy",
+ ModuleTypeUnderTest: "cc_binary",
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Blueprint: bp,
+ Filesystem: map[string]string{},
+ ExpectedBazelTargets: []string{`cc_binary(
name = "alphabet_binary",
local_includes = ["."],
srcs = ["main.cc"],
diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go
index 818d7ae..78e7b0e 100644
--- a/bp2build/symlink_forest.go
+++ b/bp2build/symlink_forest.go
@@ -1,6 +1,7 @@
package bp2build
import (
+ "android/soong/android"
"fmt"
"io/ioutil"
"os"
@@ -21,7 +22,7 @@
children map[string]*node
}
-// Ensures that the a node for the given path exists in the tree and returns it.
+// Ensures that the node for the given path exists in the tree and returns it.
func ensureNodeExists(root *node, path string) *node {
if path == "" {
return root
@@ -114,7 +115,7 @@
// contain every file in buildFilesDir and srcDir excluding the files in
// exclude. Collects every directory encountered during the traversal of srcDir
// into acc.
-func plantSymlinkForestRecursive(topdir string, forestDir string, buildFilesDir string, srcDir string, exclude *node, acc *[]string, okay *bool) {
+func plantSymlinkForestRecursive(cfg android.Config, topdir string, forestDir string, buildFilesDir string, srcDir string, exclude *node, acc *[]string, okay *bool) {
if exclude != nil && exclude.excluded {
// This directory is not needed, bail out
return
@@ -125,11 +126,11 @@
buildFilesMap := readdirToMap(shared.JoinPath(topdir, buildFilesDir))
allEntries := make(map[string]bool)
- for n, _ := range srcDirMap {
+ for n := range srcDirMap {
allEntries[n] = true
}
- for n, _ := range buildFilesMap {
+ for n := range buildFilesMap {
allEntries[n] = true
}
@@ -139,7 +140,7 @@
os.Exit(1)
}
- for f, _ := range allEntries {
+ for f := range allEntries {
if f[0] == '.' {
continue // Ignore dotfiles
}
@@ -179,7 +180,7 @@
if bDir && excludeChild != nil {
// Not in the source tree, but we have to exclude something from under
// this subtree, so descend
- plantSymlinkForestRecursive(topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
+ plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
} else {
// Not in the source tree, symlink BUILD file
symlinkIntoForest(topdir, forestChild, buildFilesChild)
@@ -188,19 +189,21 @@
if sDir && excludeChild != nil {
// Not in the build file tree, but we have to exclude something from
// under this subtree, so descend
- plantSymlinkForestRecursive(topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
+ plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
} else {
// Not in the build file tree, symlink source tree, carry on
symlinkIntoForest(topdir, forestChild, srcChild)
}
} else if sDir && bDir {
// Both are directories. Descend.
- plantSymlinkForestRecursive(topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
+ plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
} else if !sDir && !bDir {
// Neither is a directory. Prioritize BUILD files generated by bp2build
// over any BUILD file imported into external/.
- fmt.Fprintf(os.Stderr, "Both '%s' and '%s' exist, symlinking the former to '%s'\n",
- buildFilesChild, srcChild, forestChild)
+ if cfg.IsEnvTrue("BP2BUILD_VERBOSE") {
+ fmt.Fprintf(os.Stderr, "Both '%s' and '%s' exist, symlinking the former to '%s'\n",
+ buildFilesChild, srcChild, forestChild)
+ }
symlinkIntoForest(topdir, forestChild, buildFilesChild)
} else {
// Both exist and one is a file. This is an error.
@@ -216,12 +219,12 @@
// "srcDir" while excluding paths listed in "exclude". Returns the set of paths
// under srcDir on which readdir() had to be called to produce the symlink
// forest.
-func PlantSymlinkForest(topdir string, forest string, buildFiles string, srcDir string, exclude []string) []string {
+func PlantSymlinkForest(cfg android.Config, topdir string, forest string, buildFiles string, srcDir string, exclude []string) []string {
deps := make([]string, 0)
os.RemoveAll(shared.JoinPath(topdir, forest))
excludeTree := treeFromExcludePathList(exclude)
okay := true
- plantSymlinkForestRecursive(topdir, forest, buildFiles, srcDir, excludeTree, &deps, &okay)
+ plantSymlinkForestRecursive(cfg, topdir, forest, buildFiles, srcDir, excludeTree, &deps, &okay)
if !okay {
os.Exit(1)
}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 9341495..0f321de 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -53,16 +53,16 @@
return false
}
-func errored(t *testing.T, tc bp2buildTestCase, errs []error) bool {
+func errored(t *testing.T, tc Bp2buildTestCase, errs []error) bool {
t.Helper()
- if tc.expectedErr != nil {
+ if tc.ExpectedErr != nil {
// Rely on checkErrors, as this test case is expected to have an error.
return false
}
if len(errs) > 0 {
for _, err := range errs {
- t.Errorf("%s: %s", tc.description, err)
+ t.Errorf("%s: %s", tc.Description, err)
}
return true
}
@@ -71,42 +71,42 @@
return false
}
-func runBp2BuildTestCaseSimple(t *testing.T, tc bp2buildTestCase) {
+func runBp2BuildTestCaseSimple(t *testing.T, tc Bp2buildTestCase) {
t.Helper()
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
}
-type bp2buildTestCase struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- blueprint string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
+type Bp2buildTestCase struct {
+ Description string
+ ModuleTypeUnderTest string
+ ModuleTypeUnderTestFactory android.ModuleFactory
+ Blueprint string
+ ExpectedBazelTargets []string
+ Filesystem map[string]string
+ Dir string
// An error with a string contained within the string of the expected error
- expectedErr error
- unconvertedDepsMode unconvertedDepsMode
+ ExpectedErr error
+ UnconvertedDepsMode unconvertedDepsMode
}
-func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) {
+func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
t.Helper()
dir := "."
filesystem := make(map[string][]byte)
toParse := []string{
"Android.bp",
}
- for f, content := range tc.filesystem {
+ for f, content := range tc.Filesystem {
if strings.HasSuffix(f, "Android.bp") {
toParse = append(toParse, f)
}
filesystem[f] = []byte(content)
}
- config := android.TestConfig(buildDir, nil, tc.blueprint, filesystem)
+ config := android.TestConfig(buildDir, nil, tc.Blueprint, filesystem)
ctx := android.NewTestContext(config)
registerModuleTypes(ctx)
- ctx.RegisterModuleType(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestFactory)
+ ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
ctx.RegisterBp2BuildConfig(bp2buildConfig)
ctx.RegisterForBazelConversion()
@@ -120,35 +120,35 @@
}
parseAndResolveErrs := append(parseErrs, resolveDepsErrs...)
- if tc.expectedErr != nil && checkError(t, parseAndResolveErrs, tc.expectedErr) {
+ if tc.ExpectedErr != nil && checkError(t, parseAndResolveErrs, tc.ExpectedErr) {
return
}
checkDir := dir
- if tc.dir != "" {
- checkDir = tc.dir
+ if tc.Dir != "" {
+ checkDir = tc.Dir
}
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- codegenCtx.unconvertedDepMode = tc.unconvertedDepsMode
+ codegenCtx.unconvertedDepMode = tc.UnconvertedDepsMode
bazelTargets, errs := generateBazelTargetsForDir(codegenCtx, checkDir)
- if tc.expectedErr != nil {
- if checkError(t, errs, tc.expectedErr) {
+ if tc.ExpectedErr != nil {
+ if checkError(t, errs, tc.ExpectedErr) {
return
} else {
- t.Errorf("Expected error: %q, got: %q and %q", tc.expectedErr, errs, parseAndResolveErrs)
+ t.Errorf("Expected error: %q, got: %q and %q", tc.ExpectedErr, errs, parseAndResolveErrs)
}
} else {
android.FailIfErrored(t, errs)
}
- if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount {
+ if actualCount, expectedCount := len(bazelTargets), len(tc.ExpectedBazelTargets); actualCount != expectedCount {
t.Errorf("%s: Expected %d bazel target (%s), got `%d`` (%s)",
- tc.description, expectedCount, tc.expectedBazelTargets, actualCount, bazelTargets)
+ tc.Description, expectedCount, tc.ExpectedBazelTargets, actualCount, bazelTargets)
} else {
for i, target := range bazelTargets {
- if w, g := tc.expectedBazelTargets[i], target.content; w != g {
+ if w, g := tc.ExpectedBazelTargets[i], target.content; w != g {
t.Errorf(
"%s: Expected generated Bazel target to be `%s`, got `%s`",
- tc.description, w, g)
+ tc.Description, w, g)
}
}
}
@@ -173,11 +173,12 @@
Bool_prop bool
Bool_ptr_prop *bool
// Ensure that properties tagged `blueprint:mutated` are omitted
- Int_prop int `blueprint:"mutated"`
- Int64_ptr_prop *int64
- String_prop string
- String_ptr_prop *string
- String_list_prop []string
+ Int_prop int `blueprint:"mutated"`
+ Int64_ptr_prop *int64
+ String_prop string
+ String_literal_prop *string `android:"arch_variant"`
+ String_ptr_prop *string
+ String_list_prop []string
Nested_props nestedProps
Nested_props_ptr *nestedProps
@@ -213,12 +214,36 @@
return module
}
-func customModuleFactory() android.Module {
+func customModuleFactoryHostAndDevice() android.Module {
m := customModuleFactoryBase()
android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibBoth)
return m
}
+func customModuleFactoryDeviceSupported() android.Module {
+ m := customModuleFactoryBase()
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibBoth)
+ return m
+}
+
+func customModuleFactoryHostSupported() android.Module {
+ m := customModuleFactoryBase()
+ android.InitAndroidArchModule(m, android.HostSupported, android.MultilibBoth)
+ return m
+}
+
+func customModuleFactoryHostAndDeviceDefault() android.Module {
+ m := customModuleFactoryBase()
+ android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibBoth)
+ return m
+}
+
+func customModuleFactoryNeitherHostNorDeviceSupported() android.Module {
+ m := customModuleFactoryBase()
+ android.InitAndroidArchModule(m, android.NeitherHostNorDeviceSupported, android.MultilibBoth)
+ return m
+}
+
type testProps struct {
Test_prop struct {
Test_string_prop string
@@ -281,23 +306,29 @@
type customBazelModuleAttributes struct {
EmbeddedAttr
*OtherEmbeddedAttr
- String_ptr_prop *string
- String_list_prop []string
- Arch_paths bazel.LabelListAttribute
+ String_literal_prop bazel.StringAttribute
+ String_ptr_prop *string
+ String_list_prop []string
+ Arch_paths bazel.LabelListAttribute
}
func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
- paths := bazel.LabelListAttribute{}
-
if p := m.props.One_to_many_prop; p != nil && *p {
customBp2buildOneToMany(ctx, m)
return
}
+ paths := bazel.LabelListAttribute{}
+ strAttr := bazel.StringAttribute{}
for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
for config, props := range configToProps {
- if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil {
- paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, archProps.Arch_paths, archProps.Arch_paths_exclude))
+ if custProps, ok := props.(*customProps); ok {
+ if custProps.Arch_paths != nil {
+ paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, custProps.Arch_paths, custProps.Arch_paths_exclude))
+ }
+ if custProps.String_literal_prop != nil {
+ strAttr.SetSelectValue(axis, config, custProps.String_literal_prop)
+ }
}
}
}
@@ -305,10 +336,12 @@
paths.ResolveExcludes()
attrs := &customBazelModuleAttributes{
- String_ptr_prop: m.props.String_ptr_prop,
- String_list_prop: m.props.String_list_prop,
- Arch_paths: paths,
+ String_literal_prop: strAttr,
+ String_ptr_prop: m.props.String_ptr_prop,
+ String_list_prop: m.props.String_list_prop,
+ Arch_paths: paths,
}
+
attrs.Embedded_attr = m.props.Embedded_prop
if m.props.OtherEmbeddedProps != nil {
attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
@@ -355,7 +388,7 @@
}
func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
- ctx.RegisterModuleType("custom", customModuleFactory)
+ ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
ctx.RegisterForBazelConversion()
}
@@ -367,9 +400,31 @@
}`, typ, name)
}
-type attrNameToString map[string]string
+type AttrNameToString map[string]string
-func makeBazelTarget(typ, name string, attrs attrNameToString) string {
+func (a AttrNameToString) clone() AttrNameToString {
+ newAttrs := make(AttrNameToString, len(a))
+ for k, v := range a {
+ newAttrs[k] = v
+ }
+ return newAttrs
+}
+
+// makeBazelTargetNoRestrictions returns bazel target build file definition that can be host or
+// device specific, or independent of host/device.
+func makeBazelTargetHostOrDevice(typ, name string, attrs AttrNameToString, hod android.HostOrDeviceSupported) string {
+ if _, ok := attrs["target_compatible_with"]; !ok {
+ switch hod {
+ case android.HostSupported:
+ attrs["target_compatible_with"] = `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`
+ case android.DeviceSupported:
+ attrs["target_compatible_with"] = `["//build/bazel/platforms/os:android"]`
+ }
+ }
+
attrStrings := make([]string, 0, len(attrs)+1)
attrStrings = append(attrStrings, fmt.Sprintf(` name = "%s",`, name))
for _, k := range android.SortedStringKeys(attrs) {
@@ -379,3 +434,16 @@
%s
)`, typ, strings.Join(attrStrings, "\n"))
}
+
+// MakeBazelTargetNoRestrictions returns bazel target build file definition that does not add a
+// target_compatible_with. This is useful for module types like filegroup and genrule that arch not
+// arch variant
+func MakeBazelTargetNoRestrictions(typ, name string, attrs AttrNameToString) string {
+ return makeBazelTargetHostOrDevice(typ, name, attrs, android.HostAndDeviceDefault)
+}
+
+// makeBazelTargetNoRestrictions returns bazel target build file definition that is device specific
+// as this is the most common default in Soong.
+func makeBazelTarget(typ, name string, attrs AttrNameToString) string {
+ return makeBazelTargetHostOrDevice(typ, name, attrs, android.DeviceSupported)
+}
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 14b2d84..e89cc4e 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -17,6 +17,7 @@
import (
"fmt"
"io"
+ "path/filepath"
"strings"
"android/soong/android"
@@ -68,12 +69,23 @@
}
type BpfProperties struct {
- Srcs []string `android:"path"`
- Cflags []string
+ // source paths to the files.
+ Srcs []string `android:"path"`
+
+ // additional cflags that should be used to build the bpf variant of
+ // the C/C++ module.
+ Cflags []string
+
+ // directories (relative to the root of the source tree) that will
+ // be added to the include paths using -I.
Include_dirs []string
- Sub_dir string
- // If set to true, generate BTF debug info for maps & programs
- Btf *bool
+
+ // optional subdirectory under which this module is installed into.
+ Sub_dir string
+
+ // if set to true, generate BTF debug info for maps & programs.
+ Btf *bool
+
Vendor *bool
VendorInternal bool `blueprint:"mutated"`
@@ -154,6 +166,9 @@
srcs := android.PathsForModuleSrc(ctx, bpf.properties.Srcs)
for _, src := range srcs {
+ if strings.ContainsRune(filepath.Base(src.String()), '_') {
+ ctx.ModuleErrorf("invalid character '_' in source name")
+ }
obj := android.ObjPathWithExt(ctx, "unstripped", src, "o")
ctx.Build(pctx, android.BuildParams{
diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go
index 51fbc15..6e39096 100644
--- a/bpf/bpf_test.go
+++ b/bpf/bpf_test.go
@@ -30,8 +30,9 @@
cc.PrepareForTestWithCcDefaultModules,
android.FixtureMergeMockFs(
map[string][]byte{
- "bpf.c": nil,
- "BpfTest.cpp": nil,
+ "bpf.c": nil,
+ "bpf_invalid_name.c": nil,
+ "BpfTest.cpp": nil,
},
),
PrepareForTestWithBpf,
@@ -58,3 +59,15 @@
// value is not available for testing from this package.
// TODO(jungjw): Add a check for data or move this test to the cc package.
}
+
+func TestBpfSourceName(t *testing.T) {
+ bp := `
+ bpf {
+ name: "bpf_invalid_name.o",
+ srcs: ["bpf_invalid_name.c"],
+ }
+ `
+ prepareForBpfTest.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+ `\QAndroid.bp:2:3: module "bpf_invalid_name.o" variant "android_common": invalid character '_' in source name\E`)).
+ RunTestWithBp(t, bp)
+}
diff --git a/build_kzip.bash b/build_kzip.bash
index 6219021..eeef7d4 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -44,16 +44,23 @@
declare -r go_root=$(realpath prebuilts/go/linux-x86)
declare -r source_root=$PWD
-# TODO(asmundak): Until b/182183061 is fixed, default corpus has to be specified
-# in the rules file. Generate this file on the fly with corpus value set from the
-# environment variable.
-for dir in blueprint soong; do
- (cd "build/$dir";
+# For the Go code, we invoke the extractor directly. The two caveats are that
+# the extractor's rewrite rules are generated on the fly as they depend on the
+# value of XREF_CORPUS, and that the name of the kzip file is derived from the
+# directory name by replacing '/' with '_'.
+# Go extractor should succeed.
+declare -ar go_modules=(build/blueprint build/soong
+ build/make/tools/canoninja build/make/tools/compliance build/make/tools/rbcrun)
+set -e
+for dir in "${go_modules[@]}"; do
+ (cd "$dir";
+ outfile=$(echo "$dir" | sed -r 's|/|_|g;s|(.*)|\1.go.kzip|');
KYTHE_ROOT_DIRECTORY="${source_root}" "$go_extractor" --goroot="$go_root" \
--rules=<(printf '[{"pattern": "(.*)","vname": {"path": "@1@", "corpus":"%s"}}]' "${XREF_CORPUS}") \
- --canonicalize_package_corpus --output "${abspath_out}/soong/build_${dir}.go.kzip" ./...
+ --canonicalize_package_corpus --output "${abspath_out}/soong/$outfile" ./...
)
done
+set +e
declare -r kzip_count=$(find "$out" -name '*.kzip' | wc -l)
(($kzip_count>100000)) || { printf "Too few kzip files were generated: %d\n" $kzip_count; exit 1; }
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ff5ba45..47fb919 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -226,17 +226,27 @@
}
}
-func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) {
- if library.sAbiDiff.Valid() && !library.static() {
- entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", library.sAbiDiff.String())
+func (library *libraryDecorator) getAbiDiffsForAndroidMkDeps() []string {
+ if library.static() {
+ return nil
}
+ var abiDiffs []string
+ if library.sAbiDiff.Valid() {
+ abiDiffs = append(abiDiffs, library.sAbiDiff.String())
+ }
+ if library.prevSAbiDiff.Valid() {
+ abiDiffs = append(abiDiffs, library.prevSAbiDiff.String())
+ }
+ return abiDiffs
+}
+
+func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) {
+ entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", library.getAbiDiffsForAndroidMkDeps()...)
}
// TODO(ccross): remove this once apex/androidmk.go is converted to AndroidMkEntries
func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
- if library.sAbiDiff.Valid() && !library.static() {
- fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiDiff.String())
- }
+ fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", strings.Join(library.getAbiDiffsForAndroidMkDeps(), " "))
}
func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 4155aa3..61a55ee 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -20,6 +20,7 @@
"android/soong/android"
"android/soong/bazel"
+ "android/soong/cc/config"
"github.com/google/blueprint"
@@ -29,6 +30,9 @@
const (
cSrcPartition = "c"
asSrcPartition = "as"
+ asmSrcPartition = "asm"
+ lSrcPartition = "l"
+ llSrcPartition = "ll"
cppSrcPartition = "cpp"
protoSrcPartition = "proto"
)
@@ -53,6 +57,8 @@
Enabled bazel.BoolAttribute
+ Native_coverage bazel.BoolAttribute
+
sdkAttributes
}
@@ -76,6 +82,13 @@
protoSrcPartition: android.ProtoSrcLabelPartition,
cSrcPartition: bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")},
asSrcPartition: bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")},
+ asmSrcPartition: bazel.LabelPartition{Extensions: []string{".asm"}},
+ // TODO(http://b/231968910): If there is ever a filegroup target that
+ // contains .l or .ll files we will need to find a way to add a
+ // LabelMapper for these that identifies these filegroups and
+ // converts them appropriately
+ lSrcPartition: bazel.LabelPartition{Extensions: []string{".l"}},
+ llSrcPartition: bazel.LabelPartition{Extensions: []string{".ll"}},
// C++ is the "catch-all" group, and comprises generated sources because we don't
// know the language of these sources until the genrule is executed.
cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
@@ -146,7 +159,7 @@
attrs := staticOrSharedAttributes{}
setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
- attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag))
+ attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, true, filterOutStdFlag))
attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs))
@@ -278,6 +291,7 @@
// Assembly options and sources
asFlags bazel.StringListAttribute
asSrcs bazel.LabelListAttribute
+ asmSrcs bazel.LabelListAttribute
// C options and sources
conlyFlags bazel.StringListAttribute
cSrcs bazel.LabelListAttribute
@@ -285,6 +299,11 @@
cppFlags bazel.StringListAttribute
srcs bazel.LabelListAttribute
+ // Lex sources and options
+ lSrcs bazel.LabelListAttribute
+ llSrcs bazel.LabelListAttribute
+ lexopts bazel.StringListAttribute
+
hdrs bazel.LabelListAttribute
rtti bazel.BoolAttribute
@@ -311,16 +330,39 @@
return strings.HasPrefix(flag, "-std=")
}
-func parseCommandLineFlags(soongFlags []string, filterOut filterOutFn) []string {
+func filterOutClangUnknownCflags(flag string) bool {
+ for _, f := range config.ClangUnknownCflags {
+ if f == flag {
+ return true
+ }
+ }
+ return false
+}
+
+func parseCommandLineFlags(soongFlags []string, noCoptsTokenization bool, filterOut ...filterOutFn) []string {
var result []string
for _, flag := range soongFlags {
- if filterOut != nil && filterOut(flag) {
+ skipFlag := false
+ for _, filter := range filterOut {
+ if filter != nil && filter(flag) {
+ skipFlag = true
+ }
+ }
+ if skipFlag {
continue
}
// Soong's cflags can contain spaces, like `-include header.h`. For
// Bazel's copts, split them up to be compatible with the
// no_copts_tokenization feature.
- result = append(result, strings.Split(flag, " ")...)
+ if noCoptsTokenization {
+ result = append(result, strings.Split(flag, " ")...)
+ } else {
+ // Soong's Version Script and Dynamic List Properties are added as flags
+ // to Bazel's linkopts using "($location label)" syntax.
+ // Splitting on spaces would separate this into two different flags
+ // "($ location" and "label)"
+ result = append(result, flag)
+ }
}
return result
}
@@ -347,10 +389,10 @@
// overridden. In Bazel we always allow overriding, via flags; however, this can cause
// incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other
// cases.
- ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag))
- ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, nil))
- ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, nil))
- ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, nil))
+ ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, true, filterOutStdFlag, filterOutClangUnknownCflags))
+ ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, true, nil))
+ ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, true, filterOutClangUnknownCflags))
+ ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, true, filterOutClangUnknownCflags))
ca.rtti.SetSelectValue(axis, config, props.Rtti)
}
@@ -361,7 +403,8 @@
return
}
if ca.stl == nil {
- ca.stl = stlProps.Stl
+ stl := deduplicateStlInput(*stlProps.Stl)
+ ca.stl = &stl
} else if ca.stl != stlProps.Stl {
ctx.ModuleErrorf("Unsupported conversion: module with different stl for different variants: %s and %s", *ca.stl, stlProps.Stl)
}
@@ -407,6 +450,9 @@
ca.srcs = partitionedSrcs[cppSrcPartition]
ca.cSrcs = partitionedSrcs[cSrcPartition]
ca.asSrcs = partitionedSrcs[asSrcPartition]
+ ca.asmSrcs = partitionedSrcs[asmSrcPartition]
+ ca.lSrcs = partitionedSrcs[lSrcPartition]
+ ca.llSrcs = partitionedSrcs[llSrcPartition]
ca.absoluteIncludes.DeduplicateAxesFromBase()
ca.localIncludes.DeduplicateAxesFromBase()
@@ -429,32 +475,33 @@
return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), anySrcs
}
-func bp2buildResolveCppStdValue(c_std *string, cpp_std *string, gnu_extensions *bool) (*string, *string) {
- var cStdVal, cppStdVal string
+func bp2buildStdVal(std *string, prefix string, useGnu bool) *string {
+ defaultVal := prefix + "_std_default"
// If c{,pp}std properties are not specified, don't generate them in the BUILD file.
// Defaults are handled by the toolchain definition.
// However, if gnu_extensions is false, then the default gnu-to-c version must be specified.
- if cpp_std != nil {
- cppStdVal = parseCppStd(cpp_std)
- } else if gnu_extensions != nil && !*gnu_extensions {
- cppStdVal = "c++17"
- }
- if c_std != nil {
- cStdVal = parseCStd(c_std)
- } else if gnu_extensions != nil && !*gnu_extensions {
- cStdVal = "c99"
+ stdVal := proptools.StringDefault(std, defaultVal)
+ if stdVal == "experimental" || stdVal == defaultVal {
+ if stdVal == "experimental" {
+ stdVal = prefix + "_std_experimental"
+ }
+ if !useGnu {
+ stdVal += "_no_gnu"
+ }
+ } else if !useGnu {
+ stdVal = gnuToCReplacer.Replace(stdVal)
}
- cStdVal, cppStdVal = maybeReplaceGnuToC(gnu_extensions, cStdVal, cppStdVal)
- var c_std_prop, cpp_std_prop *string
- if cStdVal != "" {
- c_std_prop = &cStdVal
+ if stdVal == defaultVal {
+ return nil
}
- if cppStdVal != "" {
- cpp_std_prop = &cppStdVal
- }
+ return &stdVal
+}
- return c_std_prop, cpp_std_prop
+func bp2buildResolveCppStdValue(c_std *string, cpp_std *string, gnu_extensions *bool) (*string, *string) {
+ useGnu := useGnuExtensions(gnu_extensions)
+
+ return bp2buildStdVal(c_std, "c", useGnu), bp2buildStdVal(cpp_std, "cpp", useGnu)
}
// packageFromLabel extracts package from a fully-qualified or relative Label and whether the label
@@ -484,6 +531,61 @@
return relative, absolute
}
+type YasmAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Flags bazel.StringListAttribute
+ Include_dirs bazel.StringListAttribute
+}
+
+func bp2BuildYasm(ctx android.Bp2buildMutatorContext, m *Module, ca compilerAttributes) *bazel.LabelAttribute {
+ if ca.asmSrcs.IsEmpty() {
+ return nil
+ }
+
+ // Yasm needs the include directories from both local_includes and
+ // export_include_dirs. We don't care about actually exporting them from the
+ // yasm rule though, because they will also be present on the cc_ rule that
+ // wraps this yasm rule.
+ includes := ca.localIncludes.Clone()
+ bp2BuildPropParseHelper(ctx, m, &FlagExporterProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
+ if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
+ if len(flagExporterProperties.Export_include_dirs) > 0 {
+ x := bazel.StringListAttribute{}
+ x.SetSelectValue(axis, config, flagExporterProperties.Export_include_dirs)
+ includes.Append(x)
+ }
+ }
+ })
+
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "yasm",
+ Bzl_load_location: "//build/bazel/rules/cc:yasm.bzl",
+ },
+ android.CommonAttributes{Name: m.Name() + "_yasm"},
+ &YasmAttributes{
+ Srcs: ca.asmSrcs,
+ Flags: ca.asFlags,
+ Include_dirs: *includes,
+ })
+
+ // We only want to add a dependency on the _yasm target if there are asm
+ // sources in the current configuration. If there are unconfigured asm
+ // sources, always add the dependency. Otherwise, add the dependency only
+ // on the configuration axes and values that had asm sources.
+ if len(ca.asmSrcs.Value.Includes) > 0 {
+ return bazel.MakeLabelAttribute(":" + m.Name() + "_yasm")
+ }
+
+ ret := &bazel.LabelAttribute{}
+ for _, axis := range ca.asmSrcs.SortedConfigurationAxes() {
+ for config := range ca.asmSrcs.ConfigurableValues[axis] {
+ ret.SetSelectValue(axis, config, bazel.Label{Label: ":" + m.Name() + "_yasm"})
+ }
+ }
+ return ret
+}
+
// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module..
func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes {
archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
@@ -515,7 +617,9 @@
var allHdrs []string
if baseCompilerProps, ok := archVariantCompilerProps[axis][config].(*BaseCompilerProperties); ok {
allHdrs = baseCompilerProps.Generated_headers
-
+ if baseCompilerProps.Lex != nil {
+ compilerAttrs.lexopts.SetSelectValue(axis, config, baseCompilerProps.Lex.Flags)
+ }
(&compilerAttrs).bp2buildForAxisAndConfig(ctx, axis, config, baseCompilerProps)
}
@@ -550,10 +654,15 @@
}
}
}
-
compilerAttrs.convertStlProps(ctx, module)
(&linkerAttrs).convertStripProps(ctx, module)
+ if module.coverage != nil && module.coverage.Properties.Native_coverage != nil &&
+ !Bool(module.coverage.Properties.Native_coverage) {
+ // Native_coverage is arch neutral
+ (&linkerAttrs).features.Append(bazel.MakeStringListAttribute([]string{"-coverage"}))
+ }
+
productVariableProps := android.ProductVariableProperties(ctx)
(&compilerAttrs).convertProductVariables(ctx, productVariableProps)
@@ -562,6 +671,8 @@
(&compilerAttrs).finalize(ctx, implementationHdrs)
(&linkerAttrs).finalize(ctx)
+ (&compilerAttrs.srcs).Add(bp2BuildYasm(ctx, module, compilerAttrs))
+
protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs)
// bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know
@@ -570,6 +681,10 @@
(&linkerAttrs).wholeArchiveDeps.Add(protoDep.wholeStaticLib)
(&linkerAttrs).implementationWholeArchiveDeps.Add(protoDep.implementationWholeStaticLib)
+ convertedLSrcs := bp2BuildLex(ctx, module.Name(), compilerAttrs)
+ (&compilerAttrs).srcs.Add(&convertedLSrcs.srcName)
+ (&compilerAttrs).cSrcs.Add(&convertedLSrcs.cSrcName)
+
return baseAttributes{
compilerAttrs,
linkerAttrs,
@@ -691,7 +806,7 @@
linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--dynamic-list,$(location %s)", label.Label))
}
- la.linkopts.SetSelectValue(axis, config, linkerFlags)
+ la.linkopts.SetSelectValue(axis, config, parseCommandLineFlags(linkerFlags, false, filterOutClangUnknownCflags))
la.useLibcrt.SetSelectValue(axis, config, props.libCrt())
if axis == bazel.NoConfigAxis {
diff --git a/cc/builder.go b/cc/builder.go
index 107cd58..c289cbd 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -63,10 +63,10 @@
ld, ldRE = pctx.RemoteStaticRules("ld",
blueprint.RuleParams{
Command: "$reTemplate$ldCmd ${crtBegin} @${out}.rsp " +
- "${libFlags} ${crtEnd} -o ${out} ${ldFlags} ${extraLibFlags}",
+ "${crtEnd} -o ${out} ${ldFlags} ${extraLibFlags}",
CommandDeps: []string{"$ldCmd"},
Rspfile: "${out}.rsp",
- RspfileContent: "${in}",
+ RspfileContent: "${in} ${libFlags}",
// clang -Wl,--out-implib doesn't update its output file if it hasn't changed.
Restat: true,
},
@@ -202,36 +202,22 @@
},
"clangBin", "format")
- // Rule for invoking clang-tidy (a clang-based linter).
- clangTidyDep, clangTidyDepRE = pctx.RemoteStaticRules("clangTidyDep",
- blueprint.RuleParams{
- Depfile: "$out",
- Deps: blueprint.DepsGCC,
- Command: "${config.CcWrapper}$ccCmd $cFlags -E -o /dev/null $in " +
- "-MQ $tidyFile -MD -MF $out",
- CommandDeps: []string{"$ccCmd"},
- },
- &remoteexec.REParams{
- Labels: map[string]string{"type": "lint", "tool": "clang-tidy", "lang": "cpp"},
- ExecStrategy: "${config.REClangTidyExecStrategy}",
- Inputs: []string{"$in"},
- Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"},
- }, []string{"ccCmd", "cFlags", "tidyFile"}, []string{})
-
+ // Rules for invoking clang-tidy (a clang-based linter).
clangTidy, clangTidyRE = pctx.RemoteStaticRules("clangTidy",
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
- Command: "cp ${out}.dep ${out}.d && " +
- "$tidyVars$reTemplate${config.ClangBin}/clang-tidy $tidyFlags $in -- $cFlags && " +
- "touch $out",
- CommandDeps: []string{"${config.ClangBin}/clang-tidy"},
+ Command: "CLANG_CMD=$clangCmd TIDY_FILE=$out " +
+ "$tidyVars$reTemplate${config.ClangBin}/clang-tidy.sh $in $tidyFlags -- $cFlags",
+ CommandDeps: []string{"${config.ClangBin}/clang-tidy.sh", "$ccCmd", "$tidyCmd"},
},
&remoteexec.REParams{
Labels: map[string]string{"type": "lint", "tool": "clang-tidy", "lang": "cpp"},
ExecStrategy: "${config.REClangTidyExecStrategy}",
- Inputs: []string{"$in", "${out}.dep"},
- EnvironmentVariables: []string{"TIDY_TIMEOUT"},
+ Inputs: []string{"$in"},
+ OutputFiles: []string{"${out}", "${out}.d"},
+ ToolchainInputs: []string{"$ccCmd", "$tidyCmd"},
+ EnvironmentVariables: []string{"CLANG_CMD", "TIDY_FILE", "TIDY_TIMEOUT"},
// Although clang-tidy has an option to "fix" source files, that feature is hardly useable
// under parallel compilation and RBE. So we assume no OutputFiles here.
// The clang-tidy fix option is best run locally in single thread.
@@ -239,7 +225,7 @@
// (1) New timestamps trigger clang and clang-tidy compilations again.
// (2) Changing source files caused concurrent clang or clang-tidy jobs to crash.
Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"},
- }, []string{"cFlags", "tidyFlags", "tidyVars"}, []string{})
+ }, []string{"cFlags", "ccCmd", "clangCmd", "tidyCmd", "tidyFlags", "tidyVars"}, []string{})
_ = pctx.SourcePathVariable("yasmCmd", "prebuilts/misc/${config.HostPrebuiltTag}/yasm/yasm")
@@ -636,6 +622,7 @@
continue
}
+ // ccCmd is "clang" or "clang++"
ccDesc := ccCmd
ccCmd = "${config.ClangBin}/" + ccCmd
@@ -681,43 +668,30 @@
// Even with tidy, some src file could be skipped by noTidySrcsMap.
if tidy && !noTidySrcsMap[srcFile.String()] {
tidyFile := android.ObjPathWithExt(ctx, subdir, srcFile, "tidy")
- tidyDepFile := android.ObjPathWithExt(ctx, subdir, srcFile, "tidy.dep")
tidyFiles = append(tidyFiles, tidyFile)
+ tidyCmd := "${config.ClangBin}/clang-tidy"
- ruleDep := clangTidyDep
rule := clangTidy
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") {
- ruleDep = clangTidyDepRE
rule = clangTidyRE
}
sharedCFlags := shareFlags("cFlags", moduleFlags)
srcRelPath := srcFile.Rel()
- // Add the .tidy.d rule
- ctx.Build(pctx, android.BuildParams{
- Rule: ruleDep,
- Description: "clang-tidy-dep " + srcRelPath,
- Output: tidyDepFile,
- Input: srcFile,
- Implicits: cFlagsDeps,
- OrderOnly: pathDeps,
- Args: map[string]string{
- "ccCmd": ccCmd,
- "cFlags": sharedCFlags,
- "tidyFile": tidyFile.String(),
- },
- })
- // Add the .tidy rule with order only dependency on the .tidy.d file
+ // Add the .tidy rule
ctx.Build(pctx, android.BuildParams{
Rule: rule,
Description: "clang-tidy " + srcRelPath,
Output: tidyFile,
Input: srcFile,
Implicits: cFlagsDeps,
- OrderOnly: append(android.Paths{}, tidyDepFile),
+ OrderOnly: pathDeps,
Args: map[string]string{
"cFlags": sharedCFlags,
+ "ccCmd": ccCmd,
+ "clangCmd": ccDesc,
+ "tidyCmd": tidyCmd,
"tidyFlags": shareFlags("tidyFlags", config.TidyFlagsForSrcFile(srcFile, flags.tidyFlags)),
"tidyVars": tidyVars, // short and not shared
},
@@ -728,10 +702,8 @@
sAbiDumpFile := android.ObjPathWithExt(ctx, subdir, srcFile, "sdump")
sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile)
+ // TODO(b/226497964): dumpRule = sAbiDumpRE if USE_RBE and RBE_ABI_DUMPER are true.
dumpRule := sAbiDump
- if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_DUMPER") {
- dumpRule = sAbiDumpRE
- }
ctx.Build(pctx, android.BuildParams{
Rule: dumpRule,
Description: "header-abi-dumper " + srcFile.Rel(),
@@ -855,24 +827,13 @@
deps = append(deps, crtBegin...)
deps = append(deps, crtEnd...)
- var depFile android.WritablePath
- var depFileLdFlags string
- depsType := blueprint.DepsNone
- if !ctx.Windows() && !ctx.Darwin() {
- // lld only supports --dependency-file for elf files
- depFile = outputFile.ReplaceExtension(ctx, "d")
- depFileLdFlags = " -Wl,--dependency-file=" + depFile.String()
- depsType = blueprint.DepsGCC
- implicitOutputs = append(implicitOutputs, depFile)
- }
-
rule := ld
args := map[string]string{
"ldCmd": ldCmd,
"crtBegin": strings.Join(crtBegin.Strings(), " "),
"libFlags": strings.Join(libFlagsList, " "),
"extraLibFlags": flags.extraLibFlags,
- "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags + depFileLdFlags,
+ "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
"crtEnd": strings.Join(crtEnd.Strings(), " "),
}
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
@@ -883,8 +844,6 @@
ctx.Build(pctx, android.BuildParams{
Rule: rule,
- Deps: depsType,
- Depfile: depFile,
Description: "link " + outputFile.Base(),
Output: outputFile,
ImplicitOutputs: implicitOutputs,
@@ -957,13 +916,18 @@
return outputFile
}
-// sourceAbiDiff registers a build statement to compare linked sAbi dump files (.ldump).
+// sourceAbiDiff registers a build statement to compare linked sAbi dump files (.lsdump).
func sourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
- baseName, exportedHeaderFlags string, checkAllApis, isLlndk, isNdk, isVndkExt bool) android.OptionalPath {
+ baseName, prevVersion, exportedHeaderFlags string, diffFlags []string,
+ checkAllApis, isLlndk, isNdk, isVndkExt, previousVersionDiff bool) android.OptionalPath {
- outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
+ var outputFile android.ModuleOutPath
+ if prevVersion == "" {
+ outputFile = android.PathForModuleOut(ctx, baseName+".abidiff")
+ } else {
+ outputFile = android.PathForModuleOut(ctx, baseName+"."+prevVersion+".abidiff")
+ }
libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
- createReferenceDumpFlags := ""
var extraFlags []string
if checkAllApis {
@@ -974,22 +938,19 @@
"-allow-unreferenced-elf-symbol-changes")
}
- if exportedHeaderFlags == "" {
+ // TODO(b/241496591): Remove -advice-only after b/239792343 and b/239790286 are reolved.
+ if previousVersionDiff {
extraFlags = append(extraFlags, "-advice-only")
}
if isLlndk || isNdk {
- createReferenceDumpFlags = "--llndk"
- if isLlndk {
- // TODO(b/130324828): "-consider-opaque-types-different" should apply to
- // both LLNDK and NDK shared libs. However, a known issue in header-abi-diff
- // breaks libaaudio. Remove the if-guard after the issue is fixed.
- extraFlags = append(extraFlags, "-consider-opaque-types-different")
- }
+ extraFlags = append(extraFlags, "-consider-opaque-types-different")
}
- if isVndkExt {
+ if isVndkExt || previousVersionDiff {
extraFlags = append(extraFlags, "-allow-extensions")
}
+ // TODO(b/232891473): Simplify the above logic with diffFlags.
+ extraFlags = append(extraFlags, diffFlags...)
ctx.Build(pctx, android.BuildParams{
Rule: sAbiDiff,
@@ -1002,7 +963,7 @@
"libName": libName,
"arch": ctx.Arch().ArchType.Name,
"extraFlags": strings.Join(extraFlags, " "),
- "createReferenceDumpFlags": createReferenceDumpFlags,
+ "createReferenceDumpFlags": "",
},
})
return android.OptionalPathForPath(outputFile)
@@ -1038,33 +999,18 @@
ldCmd := "${config.ClangBin}/clang++"
- var implicitOutputs android.WritablePaths
- var depFile android.WritablePath
- var depFileLdFlags string
- depsType := blueprint.DepsNone
- if !ctx.Windows() && !ctx.Darwin() {
- // lld only supports --dependency-file for elf files
- depFile = outputFile.ReplaceExtension(ctx, "d")
- depFileLdFlags = " -Wl,--dependency-file=" + depFile.String()
- depsType = blueprint.DepsGCC
- implicitOutputs = append(implicitOutputs, depFile)
- }
-
rule := partialLd
args := map[string]string{
"ldCmd": ldCmd,
- "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags + depFileLdFlags,
+ "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
}
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
rule = partialLdRE
args["inCommaList"] = strings.Join(objFiles.Strings(), ",")
args["implicitInputs"] = strings.Join(deps.Strings(), ",")
- args["implicitOutputs"] = strings.Join(implicitOutputs.Strings(), ",")
}
ctx.Build(pctx, android.BuildParams{
Rule: rule,
- Deps: depsType,
- Depfile: depFile,
Description: "link " + outputFile.Base(),
Output: outputFile,
Inputs: objFiles,
diff --git a/cc/cc.go b/cc/cc.go
index da8a807..c71fb34 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -31,6 +31,7 @@
"android/soong/cc/config"
"android/soong/fuzz"
"android/soong/genrule"
+ "android/soong/multitree"
"android/soong/snapshot"
)
@@ -61,6 +62,8 @@
ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator).Parallel()
ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
+ ctx.TopDown("fuzz_deps", fuzzMutatorDeps)
+
ctx.BottomUp("coverage", coverageMutator).Parallel()
ctx.TopDown("afdo_deps", afdoDepsMutator)
@@ -95,6 +98,10 @@
HeaderLibs []string
RuntimeLibs []string
+ // UnexportedStaticLibs are static libraries that are also passed to -Wl,--exclude-libs= to
+ // prevent automatically exporting symbols.
+ UnexportedStaticLibs []string
+
// Used for data dependencies adjacent to tests
DataLibs []string
DataBins []string
@@ -156,6 +163,7 @@
GeneratedDeps android.Paths
Flags []string
+ LdFlags []string
IncludeDirs android.Paths
SystemIncludeDirs android.Paths
ReexportedDirs android.Paths
@@ -678,6 +686,9 @@
// Whether or not this dependency has to be followed for the apex variants
excludeInApex bool
+
+ // If true, don't automatically export symbols from the static library into a shared library.
+ unexportedSymbols bool
}
// header returns true if the libraryDependencyTag is tagging a header lib dependency.
@@ -830,6 +841,7 @@
stl *stl
sanitize *sanitize
coverage *coverage
+ fuzzer *fuzzer
sabi *sabi
vndkdep *vndkdep
lto *lto
@@ -982,6 +994,7 @@
return library.shared()
}
}
+
panic(fmt.Errorf("Shared() called on non-library module: %q", c.BaseModuleName()))
}
@@ -1154,6 +1167,9 @@
if c.coverage != nil {
c.AddProperties(c.coverage.props()...)
}
+ if c.fuzzer != nil {
+ c.AddProperties(c.fuzzer.props()...)
+ }
if c.sabi != nil {
c.AddProperties(c.sabi.props()...)
}
@@ -1671,6 +1687,7 @@
module.stl = &stl{}
module.sanitize = &sanitize{}
module.coverage = &coverage{}
+ module.fuzzer = &fuzzer{}
module.sabi = &sabi{}
module.vndkdep = &vndkdep{}
module.lto = <o{}
@@ -1789,13 +1806,20 @@
var _ android.MixedBuildBuildable = (*Module)(nil)
func (c *Module) getBazelModuleLabel(ctx android.BaseModuleContext) string {
+ var bazelModuleLabel string
if c.typ() == fullLibrary && c.static() {
// cc_library is a special case in bp2build; two targets are generated -- one for each
// of the shared and static variants. The shared variant keeps the module name, but the
// static variant uses a different suffixed name.
- return bazelLabelForStaticModule(ctx, c)
+ bazelModuleLabel = bazelLabelForStaticModule(ctx, c)
+ } else {
+ bazelModuleLabel = c.GetBazelLabel(ctx, c)
}
- return c.GetBazelLabel(ctx, c)
+ labelNoPrebuilt := bazelModuleLabel
+ if c.IsPrebuilt() {
+ labelNoPrebuilt = android.RemoveOptionalPrebuiltPrefixFromBazelLabel(bazelModuleLabel)
+ }
+ return labelNoPrebuilt
}
func (c *Module) QueueBazelCall(ctx android.BaseModuleContext) {
@@ -1885,6 +1909,9 @@
if c.coverage != nil {
flags, deps = c.coverage.flags(ctx, flags, deps)
}
+ if c.fuzzer != nil {
+ flags = c.fuzzer.flags(ctx, flags)
+ }
if c.lto != nil {
flags = c.lto.flags(ctx, flags)
}
@@ -1914,6 +1941,8 @@
flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-isystem "+dir.String())
}
+ flags.Local.LdFlags = append(flags.Local.LdFlags, deps.LdFlags...)
+
c.flags = flags
// We need access to all the flags seen by a source file.
if c.sabi != nil {
@@ -2155,6 +2184,24 @@
}
}
+func GetApiImports(c LinkableInterface, actx android.BottomUpMutatorContext) multitree.ApiImportInfo {
+ apiImportInfo := multitree.ApiImportInfo{}
+
+ if c.Device() {
+ var apiImportModule []blueprint.Module
+ if actx.OtherModuleExists("api_imports") {
+ apiImportModule = actx.AddDependency(c, nil, "api_imports")
+ if len(apiImportModule) > 0 && apiImportModule[0] != nil {
+ apiInfo := actx.OtherModuleProvider(apiImportModule[0], multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+ apiImportInfo = apiInfo
+ actx.SetProvider(multitree.ApiImportsProvider, apiInfo)
+ }
+ }
+ }
+
+ return apiImportInfo
+}
+
func GetSnapshot(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.BottomUpMutatorContext) SnapshotInfo {
// Only device modules with BOARD_VNDK_VERSION uses snapshot. Others use the zero value of
// SnapshotInfo, which provides no mappings.
@@ -2180,8 +2227,8 @@
return **snapshotInfo
}
-func RewriteSnapshotLib(lib string, snapshotMap map[string]string) string {
- if snapshot, ok := snapshotMap[lib]; ok {
+func GetReplaceModuleName(lib string, replaceMap map[string]string) string {
+ if snapshot, ok := replaceMap[lib]; ok {
return snapshot
}
@@ -2192,13 +2239,18 @@
// of names:
//
// 1. Name of an NDK library that refers to a prebuilt module.
-// For each of these, it adds the name of the prebuilt module (which will be in
-// prebuilts/ndk) to the list of nonvariant libs.
+//
+// For each of these, it adds the name of the prebuilt module (which will be in
+// prebuilts/ndk) to the list of nonvariant libs.
+//
// 2. Name of an NDK library that refers to an ndk_library module.
-// For each of these, it adds the name of the ndk_library module to the list of
-// variant libs.
+//
+// For each of these, it adds the name of the ndk_library module to the list of
+// variant libs.
+//
// 3. Anything else (so anything that isn't an NDK library).
-// It adds these to the nonvariantLibs list.
+//
+// It adds these to the nonvariantLibs list.
//
// The caller can then know to add the variantLibs dependencies differently from the
// nonvariantLibs
@@ -2210,11 +2262,11 @@
// strip #version suffix out
name, _ := StubsLibNameAndVersion(entry)
if c.InRecovery() {
- nonvariantLibs = append(nonvariantLibs, RewriteSnapshotLib(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
+ nonvariantLibs = append(nonvariantLibs, GetReplaceModuleName(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
} else if c.UseSdk() && inList(name, *getNDKKnownLibs(config)) {
variantLibs = append(variantLibs, name+ndkLibrarySuffix)
} else if c.UseVndk() {
- nonvariantLibs = append(nonvariantLibs, RewriteSnapshotLib(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
+ nonvariantLibs = append(nonvariantLibs, GetReplaceModuleName(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
} else {
// put name#version back
nonvariantLibs = append(nonvariantLibs, entry)
@@ -2223,6 +2275,25 @@
return nonvariantLibs, variantLibs
}
+func updateDepsWithApiImports(deps Deps, apiImports multitree.ApiImportInfo) Deps {
+ for idx, lib := range deps.SharedLibs {
+ deps.SharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
+ }
+
+ for idx, lib := range deps.LateSharedLibs {
+ deps.LateSharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
+ }
+
+ for idx, lib := range deps.RuntimeLibs {
+ deps.RuntimeLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
+ }
+
+ for idx, lib := range deps.HeaderLibs {
+ deps.HeaderLibs[idx] = GetReplaceModuleName(lib, apiImports.HeaderLibs)
+ }
+ return deps
+}
+
func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
if !c.Enabled() {
return
@@ -2238,6 +2309,9 @@
deps := c.deps(ctx)
+ apiImportInfo := GetApiImports(c, actx)
+ deps = updateDepsWithApiImports(deps, apiImportInfo)
+
c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs
var snapshotInfo *SnapshotInfo
@@ -2250,7 +2324,7 @@
deps.ReexportSharedLibHeaders, _ = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.ReexportSharedLibHeaders)
for idx, lib := range deps.RuntimeLibs {
- deps.RuntimeLibs[idx] = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).SharedLibs)
+ deps.RuntimeLibs[idx] = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).SharedLibs)
}
}
@@ -2260,7 +2334,7 @@
depTag.reexportFlags = true
}
- lib = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
+ lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
if c.IsStubs() {
actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
@@ -2273,10 +2347,20 @@
if c.isNDKStubLibrary() {
// NDK stubs depend on their implementation because the ABI dumps are
// generated from the implementation library.
- actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
- c.ImageVariation(),
- blueprint.Variation{Mutator: "link", Variation: "shared"},
- ), stubImplementation, c.BaseModuleName())
+ apiImportName := c.BaseModuleName() + multitree.GetApiImportSuffix()
+
+ // If original library exists as imported API, set dependency on the imported library
+ if actx.OtherModuleExists(apiImportName) {
+ actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
+ c.ImageVariation(),
+ blueprint.Variation{Mutator: "link", Variation: "shared"},
+ ), stubImplementation, apiImportName)
+ } else {
+ actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
+ c.ImageVariation(),
+ blueprint.Variation{Mutator: "link", Variation: "shared"},
+ ), stubImplementation, c.BaseModuleName())
+ }
}
// sysprop_library has to support both C++ and Java. So sysprop_library internally creates one
@@ -2292,7 +2376,7 @@
lib = impl
}
- lib = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
+ lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
@@ -2312,7 +2396,7 @@
lib = impl
}
- lib = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
+ lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
@@ -2326,7 +2410,7 @@
depTag := libraryDependencyTag{Kind: staticLibraryDependency, staticUnwinder: true}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
- }, depTag, RewriteSnapshotLib(staticUnwinder(actx), GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+ }, depTag, GetReplaceModuleName(staticUnwinder(actx), GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
}
// shared lib names without the #version suffix
@@ -2358,7 +2442,14 @@
depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
- }, depTag, RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+ }, depTag, GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+ }
+
+ for _, lib := range deps.UnexportedStaticLibs {
+ depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency, unexportedSymbols: true}
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "static"},
+ }, depTag, GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
}
for _, lib := range deps.LateSharedLibs {
@@ -2399,11 +2490,11 @@
actx.AddVariationDependencies(crtVariations, objDepTag, deps.ObjFiles...)
for _, crt := range deps.CrtBegin {
actx.AddVariationDependencies(crtVariations, CrtBeginDepTag,
- RewriteSnapshotLib(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
+ GetReplaceModuleName(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
}
for _, crt := range deps.CrtEnd {
actx.AddVariationDependencies(crtVariations, CrtEndDepTag,
- RewriteSnapshotLib(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
+ GetReplaceModuleName(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
}
if deps.DynamicLinker != "" {
actx.AddDependency(c, dynamicLinkerDepTag, deps.DynamicLinker)
@@ -2428,7 +2519,7 @@
actx.AddVariationDependencies([]blueprint.Variation{
c.ImageVariation(),
{Mutator: "link", Variation: "shared"},
- }, vndkExtDepTag, RewriteSnapshotLib(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs))
+ }, vndkExtDepTag, GetReplaceModuleName(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs))
}
}
}
@@ -2859,6 +2950,10 @@
panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
}
}
+ if libDepTag.unexportedSymbols {
+ depPaths.LdFlags = append(depPaths.LdFlags,
+ "-Wl,--exclude-libs="+staticLibraryInfo.StaticLibrary.Base())
+ }
}
if libDepTag.static() && !libDepTag.wholeStatic {
@@ -3146,6 +3241,11 @@
return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix()
}
+
+ // Remove API import suffix if exists
+ if _, ok := ccDepModule.linker.(*apiLibraryDecorator); ok {
+ libName = strings.TrimSuffix(libName, multitree.GetApiImportSuffix())
+ }
}
if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() &&
@@ -3481,6 +3581,10 @@
if _, ok := c.linker.(prebuiltLinkerInterface); ok {
return nil
}
+ if _, ok := c.linker.(*apiLibraryDecorator); ok {
+ return nil
+ }
+
minSdkVersion := c.MinSdkVersion()
if minSdkVersion == "apex_inherit" {
return nil
@@ -3598,9 +3702,7 @@
}
}
-//
// Defaults
-//
type Defaults struct {
android.ModuleBase
android.DefaultsModuleBase
diff --git a/cc/cc_test.go b/cc/cc_test.go
index fb24624..792a8e0 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -20,6 +20,7 @@
"path/filepath"
"reflect"
"regexp"
+ "runtime"
"strings"
"testing"
@@ -3342,6 +3343,127 @@
`)
}
+func VerifyAFLFuzzTargetVariant(t *testing.T, variant string) {
+ bp := `
+ cc_fuzz {
+ name: "test_afl_fuzz_target",
+ srcs: ["foo.c"],
+ host_supported: true,
+ static_libs: [
+ "afl_fuzz_static_lib",
+ ],
+ shared_libs: [
+ "afl_fuzz_shared_lib",
+ ],
+ fuzzing_frameworks: {
+ afl: true,
+ libfuzzer: false,
+ },
+ }
+ cc_library {
+ name: "afl_fuzz_static_lib",
+ host_supported: true,
+ srcs: ["static_file.c"],
+ }
+ cc_library {
+ name: "libfuzzer_only_static_lib",
+ host_supported: true,
+ srcs: ["static_file.c"],
+ }
+ cc_library {
+ name: "afl_fuzz_shared_lib",
+ host_supported: true,
+ srcs: ["shared_file.c"],
+ static_libs: [
+ "second_static_lib",
+ ],
+ }
+ cc_library_headers {
+ name: "libafl_headers",
+ vendor_available: true,
+ host_supported: true,
+ export_include_dirs: [
+ "include",
+ "instrumentation",
+ ],
+ }
+ cc_object {
+ name: "afl-compiler-rt",
+ vendor_available: true,
+ host_supported: true,
+ cflags: [
+ "-fPIC",
+ ],
+ srcs: [
+ "instrumentation/afl-compiler-rt.o.c",
+ ],
+ }
+ cc_library {
+ name: "second_static_lib",
+ host_supported: true,
+ srcs: ["second_file.c"],
+ }
+ cc_object {
+ name: "aflpp_driver",
+ host_supported: true,
+ srcs: [
+ "aflpp_driver.c",
+ ],
+ }`
+
+ testEnv := map[string]string{
+ "FUZZ_FRAMEWORK": "AFL",
+ }
+
+ ctx := android.GroupFixturePreparers(prepareForCcTest, android.FixtureMergeEnv(testEnv)).RunTestWithBp(t, bp)
+
+ checkPcGuardFlag := func(
+ modName string, variantName string, shouldHave bool) {
+ cc := ctx.ModuleForTests(modName, variantName).Rule("cc")
+
+ cFlags, ok := cc.Args["cFlags"]
+ if !ok {
+ t.Errorf("Could not find cFlags for module %s and variant %s",
+ modName, variantName)
+ }
+
+ if strings.Contains(
+ cFlags, "-fsanitize-coverage=trace-pc-guard") != shouldHave {
+ t.Errorf("Flag was found: %t. Expected to find flag: %t. "+
+ "Test failed for module %s and variant %s",
+ !shouldHave, shouldHave, modName, variantName)
+ }
+ }
+
+ moduleName := "test_afl_fuzz_target"
+ checkPcGuardFlag(moduleName, variant+"_fuzzer", true)
+
+ moduleName = "afl_fuzz_static_lib"
+ checkPcGuardFlag(moduleName, variant+"_static", false)
+ checkPcGuardFlag(moduleName, variant+"_static_fuzzer", true)
+
+ moduleName = "second_static_lib"
+ checkPcGuardFlag(moduleName, variant+"_static", false)
+ checkPcGuardFlag(moduleName, variant+"_static_fuzzer", true)
+
+ ctx.ModuleForTests("afl_fuzz_shared_lib",
+ "android_arm64_armv8-a_shared").Rule("cc")
+ ctx.ModuleForTests("afl_fuzz_shared_lib",
+ "android_arm64_armv8-a_shared_fuzzer").Rule("cc")
+}
+
+func TestAFLFuzzTargetForDevice(t *testing.T) {
+ VerifyAFLFuzzTargetVariant(t, "android_arm64_armv8-a")
+}
+
+func TestAFLFuzzTargetForLinuxHost(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("requires linux")
+ }
+
+ VerifyAFLFuzzTargetVariant(t, "linux_glibc_x86_64")
+}
+
// Simple smoke test for the cc_fuzz target that ensures the rule compiles
// correctly.
func TestFuzzTarget(t *testing.T) {
@@ -3722,6 +3844,25 @@
android.AssertStringDoesContain(t, "min sdk version", cFlags, "-target aarch64-linux-android29")
}
+func TestNonDigitMinSdkVersionInClangTriple(t *testing.T) {
+ bp := `
+ cc_library_shared {
+ name: "libfoo",
+ srcs: ["foo.c"],
+ min_sdk_version: "S",
+ }
+ `
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_version_active_codenames = []string{"UpsideDownCake", "Tiramisu"}
+ }),
+ ).RunTestWithBp(t, bp)
+ ctx := result.TestContext
+ cFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"]
+ android.AssertStringDoesContain(t, "min sdk version", cFlags, "-target aarch64-linux-android31")
+}
+
func TestIncludeDirsExporting(t *testing.T) {
// Trim spaces from the beginning, end and immediately after any newline characters. Leaves
@@ -4076,7 +4217,7 @@
{
name: "assemble",
src: "foo.s",
- expected: combineSlices(baseExpectedFlags, []string{"-D__ASSEMBLY__"}, expectedIncludes, lastIncludes),
+ expected: combineSlices(baseExpectedFlags, []string{"${config.CommonGlobalAsflags}"}, expectedIncludes, lastIncludes),
},
}
diff --git a/cc/compiler.go b/cc/compiler.go
index 773a642..3c904b8 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -295,8 +295,12 @@
getNamedMapForConfig(ctx.Config(), key).Store(module, true)
}
+func useGnuExtensions(gnuExtensions *bool) bool {
+ return proptools.BoolDefault(gnuExtensions, true)
+}
+
func maybeReplaceGnuToC(gnuExtensions *bool, cStd string, cppStd string) (string, string) {
- if gnuExtensions != nil && *gnuExtensions == false {
+ if !useGnuExtensions(gnuExtensions) {
cStd = gnuToCReplacer.Replace(cStd)
cppStd = gnuToCReplacer.Replace(cppStd)
}
@@ -453,7 +457,8 @@
if version == "" || version == "current" {
target += strconv.Itoa(android.FutureApiLevelInt)
} else {
- target += version
+ apiLevel := nativeApiLevelOrPanic(ctx, version)
+ target += apiLevel.String()
}
}
@@ -489,7 +494,7 @@
}
}
- flags.Global.AsFlags = append(flags.Global.AsFlags, "-D__ASSEMBLY__")
+ flags.Global.AsFlags = append(flags.Global.AsFlags, "${config.CommonGlobalAsflags}")
flags.Global.CppFlags = append(flags.Global.CppFlags, tc.Cppflags())
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
index 1a21c13..64a121e 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -24,6 +24,7 @@
"x86_device.go",
"x86_64_device.go",
+ "arm_linux_host.go",
"darwin_host.go",
"x86_linux_host.go",
"x86_linux_bionic_host.go",
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index dfe143f..66087e6 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -33,9 +33,7 @@
},
"armv8-a-branchprot": []string{
"-march=armv8-a",
- // Disable BTI until drm vendors stop using OS libraries as sources
- // of gadgets (https://issuetracker.google.com/216395195).
- "-mbranch-protection=pac-ret",
+ "-mbranch-protection=standard",
},
"armv8-2a": []string{
"-march=armv8.2-a",
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
index 5c7f926..2d316e6 100644
--- a/cc/config/arm64_linux_host.go
+++ b/cc/config/arm64_linux_host.go
@@ -64,25 +64,25 @@
// toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android
// target. The overridden methods below show the differences.
-type toolchainLinuxArm64 struct {
+type toolchainLinuxBionicArm64 struct {
toolchainArm64
}
-func (toolchainLinuxArm64) ClangTriple() string {
+func (toolchainLinuxBionicArm64) ClangTriple() string {
// Note the absence of "-android" suffix. The compiler won't define __ANDROID__
return "aarch64-linux"
}
-func (toolchainLinuxArm64) Cflags() string {
+func (toolchainLinuxBionicArm64) Cflags() string {
// The inherited flags + extra flags
return "${config.Arm64Cflags} ${config.LinuxBionicArm64Cflags}"
}
-func (toolchainLinuxArm64) CrtBeginSharedBinary() []string {
+func (toolchainLinuxBionicArm64) CrtBeginSharedBinary() []string {
return linuxArm64CrtBeginSharedBinary
}
-func linuxArm64ToolchainFactory(arch android.Arch) Toolchain {
+func linuxBionicArm64ToolchainFactory(arch android.Arch) Toolchain {
archVariant := "armv8-a" // for host, default to armv8-a
toolchainCflags := []string{arm64ArchVariantCflagsVar[archVariant]}
@@ -90,7 +90,7 @@
// the host CPU needs the fix
extraLdflags := "-Wl,--fix-cortex-a53-843419"
- ret := toolchainLinuxArm64{}
+ ret := toolchainLinuxBionicArm64{}
// add the extra ld and lld flags
ret.toolchainArm64.ldflags = strings.Join([]string{
@@ -108,5 +108,5 @@
}
func init() {
- registerToolchainFactory(android.LinuxBionic, android.Arm64, linuxArm64ToolchainFactory)
+ registerToolchainFactory(android.LinuxBionic, android.Arm64, linuxBionicArm64ToolchainFactory)
}
diff --git a/cc/config/arm_linux_host.go b/cc/config/arm_linux_host.go
new file mode 100644
index 0000000..525fb5d
--- /dev/null
+++ b/cc/config/arm_linux_host.go
@@ -0,0 +1,174 @@
+// 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 config
+
+import "android/soong/android"
+
+var (
+ linuxArmCflags = []string{
+ "-march=armv7a",
+ }
+
+ linuxArm64Cflags = []string{}
+
+ linuxArmLdflags = []string{
+ "-march=armv7a",
+ }
+
+ linuxArm64Ldflags = []string{}
+)
+
+func init() {
+ exportedVars.ExportStringListStaticVariable("LinuxArmCflags", linuxArmCflags)
+ exportedVars.ExportStringListStaticVariable("LinuxArm64Cflags", linuxArm64Cflags)
+ exportedVars.ExportStringListStaticVariable("LinuxArmLdflags", linuxArmLdflags)
+ exportedVars.ExportStringListStaticVariable("LinuxArmLldflags", linuxArmLdflags)
+ exportedVars.ExportStringListStaticVariable("LinuxArm64Ldflags", linuxArm64Ldflags)
+ exportedVars.ExportStringListStaticVariable("LinuxArm64Lldflags", linuxArm64Ldflags)
+
+ exportedVars.ExportStringListStaticVariable("LinuxArmYasmFlags", []string{"-f elf32 -m arm"})
+ exportedVars.ExportStringListStaticVariable("LinuxArm64YasmFlags", []string{"-f elf64 -m aarch64"})
+
+}
+
+// Musl arm+arm64
+type toolchainLinuxArm struct {
+ toolchain32Bit
+ toolchainLinux
+}
+
+type toolchainLinuxArm64 struct {
+ toolchain64Bit
+ toolchainLinux
+}
+
+func (t *toolchainLinuxArm) Name() string {
+ return "arm"
+}
+
+func (t *toolchainLinuxArm64) Name() string {
+ return "arm64"
+}
+
+func (t *toolchainLinuxArm) Cflags() string {
+ return "${config.LinuxCflags} ${config.LinuxArmCflags}"
+}
+
+func (t *toolchainLinuxArm) Cppflags() string {
+ return ""
+}
+
+func (t *toolchainLinuxArm64) Cflags() string {
+ return "${config.LinuxCflags} ${config.LinuxArm64Cflags}"
+}
+
+func (t *toolchainLinuxArm64) Cppflags() string {
+ return ""
+}
+
+func (t *toolchainLinuxArm) Ldflags() string {
+ return "${config.LinuxLdflags} ${config.LinuxArmLdflags}"
+}
+
+func (t *toolchainLinuxArm) Lldflags() string {
+ return "${config.LinuxLldflags} ${config.LinuxArmLldflags}"
+}
+
+func (t *toolchainLinuxArm64) Ldflags() string {
+ return "${config.LinuxLdflags} ${config.LinuxArm64Ldflags}"
+}
+
+func (t *toolchainLinuxArm64) Lldflags() string {
+ return "${config.LinuxLldflags} ${config.LinuxArm64Lldflags}"
+}
+
+func (t *toolchainLinuxArm) YasmFlags() string {
+ return "${config.LinuxArmYasmFlags}"
+}
+
+func (t *toolchainLinuxArm64) YasmFlags() string {
+ return "${config.LinuxArm64YasmFlags}"
+}
+
+func (toolchainLinuxArm) LibclangRuntimeLibraryArch() string {
+ return "arm"
+}
+
+func (toolchainLinuxArm64) LibclangRuntimeLibraryArch() string {
+ return "arm64"
+}
+
+func (t *toolchainLinuxArm) InstructionSetFlags(isa string) (string, error) {
+ // TODO: Is no thumb OK?
+ return t.toolchainBase.InstructionSetFlags("")
+}
+
+type toolchainLinuxMuslArm struct {
+ toolchainLinuxArm
+ toolchainMusl
+}
+
+type toolchainLinuxMuslArm64 struct {
+ toolchainLinuxArm64
+ toolchainMusl
+}
+
+func (t *toolchainLinuxMuslArm) ClangTriple() string {
+ return "arm-linux-musleabihf"
+}
+
+func (t *toolchainLinuxMuslArm) Cflags() string {
+ return t.toolchainLinuxArm.Cflags() + " " + t.toolchainMusl.Cflags()
+}
+
+func (t *toolchainLinuxMuslArm) Ldflags() string {
+ return t.toolchainLinuxArm.Ldflags() + " " + t.toolchainMusl.Ldflags()
+}
+
+func (t *toolchainLinuxMuslArm) Lldflags() string {
+ return t.toolchainLinuxArm.Lldflags() + " " + t.toolchainMusl.Lldflags()
+}
+
+func (t *toolchainLinuxMuslArm64) ClangTriple() string {
+ return "aarch64-linux-musl"
+}
+
+func (t *toolchainLinuxMuslArm64) Cflags() string {
+ return t.toolchainLinuxArm64.Cflags() + " " + t.toolchainMusl.Cflags()
+}
+
+func (t *toolchainLinuxMuslArm64) Ldflags() string {
+ return t.toolchainLinuxArm64.Ldflags() + " " + t.toolchainMusl.Ldflags()
+}
+
+func (t *toolchainLinuxMuslArm64) Lldflags() string {
+ return t.toolchainLinuxArm64.Lldflags() + " " + t.toolchainMusl.Lldflags()
+}
+
+var toolchainLinuxMuslArmSingleton Toolchain = &toolchainLinuxMuslArm{}
+var toolchainLinuxMuslArm64Singleton Toolchain = &toolchainLinuxMuslArm64{}
+
+func linuxMuslArmToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxMuslArmSingleton
+}
+
+func linuxMuslArm64ToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxMuslArm64Singleton
+}
+
+func init() {
+ registerToolchainFactory(android.LinuxMusl, android.Arm, linuxMuslArmToolchainFactory)
+ registerToolchainFactory(android.LinuxMusl, android.Arm64, linuxMuslArm64ToolchainFactory)
+}
diff --git a/cc/config/global.go b/cc/config/global.go
index 178e80b..357ea44 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -59,6 +59,10 @@
"-Werror=string-plus-int",
"-Werror=unreachable-code-loop-increment",
+ // Force deprecation warnings to be warnings for code that compiles with -Werror.
+ // Making deprecated usages an error causes extreme pain when trying to deprecate anything.
+ "-Wno-error=deprecated-declarations",
+
"-D__compiler_offsetof=__builtin_offsetof",
// Emit address-significance table which allows linker to perform safe ICF. Clang does
@@ -117,6 +121,13 @@
commonGlobalConlyflags = []string{}
+ commonGlobalAsflags = []string{
+ "-D__ASSEMBLY__",
+ // TODO(b/235105792): override global -fdebug-default-version=5, it is causing $TMPDIR to
+ // end up in the dwarf data for crtend_so.S.
+ "-fdebug-default-version=4",
+ }
+
deviceGlobalCflags = []string{
"-ffunction-sections",
"-fdata-sections",
@@ -221,7 +232,6 @@
// New warnings to be fixed after clang-r383902.
"-Wno-deprecated-copy", // http://b/153746672
"-Wno-range-loop-construct", // http://b/153747076
- "-Wno-misleading-indentation", // http://b/153746954
"-Wno-zero-as-null-pointer-constant", // http://b/68236239
"-Wno-deprecated-anon-enum-enum-conversion", // http://b/153746485
"-Wno-pessimizing-move", // http://b/154270751
@@ -232,6 +242,8 @@
// New warnings to be fixed after clang-r433403
"-Wno-error=unused-but-set-variable", // http://b/197240255
"-Wno-error=unused-but-set-parameter", // http://b/197240255
+ // New warnings to be fixed after clang-r458507
+ "-Wno-error=unqualified-std-cast-call", // http://b/239662094
}
noOverrideExternalGlobalCflags = []string{
@@ -240,6 +252,8 @@
"-Wno-unused-but-set-parameter",
// http://b/215753485
"-Wno-bitwise-instead-of-logical",
+ // http://b/232926688
+ "-Wno-misleading-indentation",
}
// Extra cflags for external third-party projects to disable warnings that
@@ -271,8 +285,13 @@
// http://b/175068488
"-Wno-string-concatenation",
+
+ // http://b/239661264
+ "-Wno-deprecated-non-prototype",
}
+ llvmNextExtraCommonGlobalCflags = []string{}
+
IllegalFlags = []string{
"-w",
}
@@ -284,8 +303,8 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r450784e"
- ClangDefaultShortVersion = "14.0.7"
+ ClangDefaultVersion = "clang-r458507"
+ ClangDefaultShortVersion = "15.0.1"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
@@ -313,6 +332,7 @@
}
exportedVars.ExportStringListStaticVariable("CommonGlobalConlyflags", commonGlobalConlyflags)
+ exportedVars.ExportStringListStaticVariable("CommonGlobalAsflags", commonGlobalAsflags)
exportedVars.ExportStringListStaticVariable("DeviceGlobalCppflags", deviceGlobalCppflags)
exportedVars.ExportStringListStaticVariable("DeviceGlobalLdflags", deviceGlobalLdflags)
exportedVars.ExportStringListStaticVariable("DeviceGlobalLldflags", deviceGlobalLldflags)
@@ -353,6 +373,15 @@
if ctx.Config().IsEnvTrue("USE_CCACHE") {
flags = append(flags, "-Wno-unused-command-line-argument")
}
+
+ if ctx.Config().IsEnvTrue("LLVM_NEXT") {
+ flags = append(flags, llvmNextExtraCommonGlobalCflags...)
+ }
+
+ if ctx.Config().IsEnvTrue("ALLOW_UNKNOWN_WARNING_OPTION") {
+ flags = append(flags, "-Wno-error=unknown-warning-option")
+ }
+
return strings.Join(flags, " ")
})
@@ -370,6 +399,11 @@
exportedVars.ExportStringListStaticVariable("CommonGlobalCppflags", commonGlobalCppflags)
exportedVars.ExportStringListStaticVariable("ExternalCflags", extraExternalCflags)
+ exportedVars.ExportString("CStdVersion", CStdVersion)
+ exportedVars.ExportString("CppStdVersion", CppStdVersion)
+ exportedVars.ExportString("ExperimentalCStdVersion", ExperimentalCStdVersion)
+ exportedVars.ExportString("ExperimentalCppStdVersion", ExperimentalCppStdVersion)
+
// Everything in these lists is a crime against abstraction and dependency tracking.
// Do not add anything to this list.
commonGlobalIncludes := []string{
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index 826197a..232e686 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -19,6 +19,43 @@
"strings"
)
+var (
+ // Some clang-tidy checks have bugs or don't work for Android.
+ // They are disabled here, overriding any locally selected checks.
+ globalNoCheckList = []string{
+ // https://b.corp.google.com/issues/153464409
+ // many local projects enable cert-* checks, which
+ // trigger bugprone-reserved-identifier.
+ "-bugprone-reserved-identifier*,-cert-dcl51-cpp,-cert-dcl37-c",
+ // http://b/153757728
+ "-readability-qualified-auto",
+ // http://b/193716442
+ "-bugprone-implicit-widening-of-multiplication-result",
+ // Too many existing functions trigger this rule, and fixing it requires large code
+ // refactoring. The cost of maintaining this tidy rule outweighs the benefit it brings.
+ "-bugprone-easily-swappable-parameters",
+ // http://b/216364337 - TODO: Follow-up after compiler update to
+ // disable or fix individual instances.
+ "-cert-err33-c",
+ // http://b/241125373
+ "-bugprone-unchecked-optional-access",
+ }
+
+ // Some clang-tidy checks are included in some tidy_checks_as_errors lists,
+ // but not all warnings are fixed/suppressed yet. These checks are not
+ // disabled in the TidyGlobalNoChecks list, so we can see them and fix/suppress them.
+ globalNoErrorCheckList = []string{
+ // http://b/241997913
+ "-bugprone-assignment-in-if-condition",
+ // http://b/155034972
+ "-bugprone-branch-clone",
+ // http://b/155034563
+ "-bugprone-signed-char-misuse",
+ // http://b/241819232
+ "-misc-const-correctness",
+ }
+)
+
func init() {
// Many clang-tidy checks like altera-*, llvm-*, modernize-*
// are not designed for Android source code or creating too
@@ -49,8 +86,10 @@
"misc-*",
"performance-*",
"portability-*",
+ "-bugprone-assignment-in-if-condition",
"-bugprone-easily-swappable-parameters",
"-bugprone-narrowing-conversions",
+ "-misc-const-correctness",
"-misc-no-recursion",
"-misc-non-private-member-variables-in-classes",
"-misc-unused-parameters",
@@ -94,6 +133,14 @@
}, ",")
})
+ pctx.VariableFunc("TidyGlobalNoChecks", func(ctx android.PackageVarContext) string {
+ return strings.Join(globalNoCheckList, ",")
+ })
+
+ pctx.VariableFunc("TidyGlobalNoErrorChecks", func(ctx android.PackageVarContext) string {
+ return strings.Join(globalNoErrorCheckList, ",")
+ })
+
// To reduce duplicate warnings from the same header files,
// header-filter will contain only the module directory and
// those specified by DEFAULT_TIDY_HEADER_DIRS.
@@ -152,6 +199,22 @@
return tidyDefault
}
+// Returns a globally disabled tidy checks, overriding locally selected checks.
+func TidyGlobalNoChecks() string {
+ if len(globalNoCheckList) > 0 {
+ return ",${config.TidyGlobalNoChecks}"
+ }
+ return ""
+}
+
+// Returns a globally allowed/no-error tidy checks, appended to -warnings-as-errors.
+func TidyGlobalNoErrorChecks() string {
+ if len(globalNoErrorCheckList) > 0 {
+ return ",${config.TidyGlobalNoErrorChecks}"
+ }
+ return ""
+}
+
func TidyFlagsForSrcFile(srcFile android.Path, flags string) string {
// Disable clang-analyzer-* checks globally for generated source files
// because some of them are too huge. Local .bp files can add wanted
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 492cd98..dd612ce 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -17,100 +17,9 @@
// List of VNDK libraries that have different core variant and vendor variant.
// For these libraries, the vendor variants must be installed even if the device
// has VndkUseCoreVariant set.
-// TODO(b/150578172): clean up unstable and non-versioned aidl module
+// Note that AIDL-generated modules must use vendor variants by default.
var VndkMustUseVendorVariantList = []string{
- "android.hardware.authsecret-V1-ndk",
- "android.hardware.authsecret-V1-ndk_platform",
- "android.hardware.authsecret-ndk_platform",
- "android.hardware.authsecret-unstable-ndk_platform",
- "android.hardware.automotive.occupant_awareness-V1-ndk",
- "android.hardware.automotive.occupant_awareness-V1-ndk_platform",
- "android.hardware.automotive.occupant_awareness-ndk_platform",
- "android.hardware.gnss-V1-ndk",
- "android.hardware.gnss-V1-ndk_platform",
- "android.hardware.gnss-ndk_platform",
- "android.hardware.gnss-unstable-ndk_platform",
- "android.hardware.health-V1-ndk",
- "android.hardware.health-ndk",
- "android.hardware.health.storage-V1-ndk",
- "android.hardware.health.storage-V1-ndk_platform",
- "android.hardware.health.storage-ndk_platform",
- "android.hardware.health.storage-unstable-ndk_platform",
- "android.hardware.identity-V2-ndk_platform",
- "android.hardware.identity-V3-ndk",
- "android.hardware.identity-V3-ndk_platform",
- "android.hardware.identity-ndk_platform",
- "android.hardware.light-V1-ndk",
- "android.hardware.light-V1-ndk_platform",
- "android.hardware.light-ndk_platform",
- "android.hardware.memtrack-V1-ndk",
- "android.hardware.memtrack-V1-ndk_platform",
- "android.hardware.memtrack-ndk_platform",
- "android.hardware.memtrack-unstable-ndk_platform",
"android.hardware.nfc@1.2",
- "android.hardware.oemlock-V1-ndk",
- "android.hardware.oemlock-V1-ndk_platform",
- "android.hardware.oemlock-ndk_platform",
- "android.hardware.oemlock-unstable-ndk_platform",
- "android.hardware.power-V1-ndk_platform",
- "android.hardware.power-V2-ndk",
- "android.hardware.power-V2-ndk_platform",
- "android.hardware.power-ndk_platform",
- "android.hardware.power.stats-V1-ndk",
- "android.hardware.power.stats-V1-ndk_platform",
- "android.hardware.power.stats-ndk_platform",
- "android.hardware.power.stats-unstable-ndk_platform",
- "android.hardware.rebootescrow-V1-ndk",
- "android.hardware.rebootescrow-V1-ndk_platform",
- "android.hardware.rebootescrow-ndk_platform",
- "android.hardware.radio-V1-ndk",
- "android.hardware.radio-V1-ndk_platform",
- "android.hardware.radio.config-V1-ndk",
- "android.hardware.radio.config-V1-ndk_platform",
- "android.hardware.radio.data-V1-ndk",
- "android.hardware.radio.data-V1-ndk_platform",
- "android.hardware.radio.messaging-V1-ndk",
- "android.hardware.radio.messaging-V1-ndk_platform",
- "android.hardware.radio.modem-V1-ndk",
- "android.hardware.radio.modem-V1-ndk_platform",
- "android.hardware.radio.network-V1-ndk",
- "android.hardware.radio.network-V1-ndk_platform",
- "android.hardware.radio.sim-V1-ndk",
- "android.hardware.radio.sim-V1-ndk_platform",
- "android.hardware.radio.voice-V1-ndk",
- "android.hardware.radio.voice-V1-ndk_platform",
- "android.hardware.security.keymint-V1-ndk",
- "android.hardware.security.keymint-V1-ndk_platform",
- "android.hardware.security.keymint-ndk_platform",
- "android.hardware.security.keymint-unstable-ndk_platform",
- "android.hardware.security.secureclock-V1-ndk",
- "android.hardware.security.secureclock-V1-ndk_platform",
- "android.hardware.security.secureclock-ndk_platform",
- "android.hardware.security.secureclock-unstable-ndk_platform",
- "android.hardware.security.sharedsecret-V1-ndk",
- "android.hardware.security.sharedsecret-V1-ndk_platform",
- "android.hardware.security.sharedsecret-ndk_platform",
- "android.hardware.security.sharedsecret-unstable-ndk_platform",
- "android.hardware.vibrator-V1-ndk_platform",
- "android.hardware.vibrator-V2-ndk",
- "android.hardware.vibrator-V2-ndk_platform",
- "android.hardware.vibrator-ndk_platform",
- "android.hardware.weaver-V1-ndk",
- "android.hardware.weaver-V1-ndk_platform",
- "android.hardware.weaver-ndk_platform",
- "android.hardware.weaver-unstable-ndk_platform",
- "android.system.suspend-V1-ndk",
- "android.system.keystore2-V1-ndk",
- "android.se.omapi-V1-ndk_platform",
- "android.se.omapi-ndk_platform",
- "android.se.omapi-unstable-ndk_platform",
- "android.hardware.wifi.hostapd-V1-ndk",
- "android.hardware.wifi.hostapd-V1-ndk_platform",
- "android.hardware.wifi.supplicant-V1-ndk",
- "android.system.keystore2-V1-ndk_platform",
- "android.system.keystore2-ndk_platform",
- "android.system.keystore2-unstable-ndk_platform",
- "android.system.suspend-V1-ndk_platform",
"libbinder",
"libcrypto",
"libexpat",
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 23d81d6..dfc718e 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -27,28 +27,81 @@
)
func init() {
- android.RegisterModuleType("cc_fuzz", FuzzFactory)
+ android.RegisterModuleType("cc_fuzz", LibFuzzFactory)
android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
}
+type FuzzProperties struct {
+ FuzzFramework fuzz.Framework `blueprint:"mutated"`
+}
+
+type fuzzer struct {
+ Properties FuzzProperties
+}
+
+func (fuzzer *fuzzer) flags(ctx ModuleContext, flags Flags) Flags {
+ if fuzzer.Properties.FuzzFramework == fuzz.AFL {
+ flags.Local.CFlags = append(flags.Local.CFlags, []string{
+ "-fsanitize-coverage=trace-pc-guard",
+ "-Wno-unused-result",
+ "-Wno-unused-parameter",
+ "-Wno-unused-function",
+ }...)
+ }
+
+ return flags
+}
+
+func (fuzzer *fuzzer) props() []interface{} {
+ return []interface{}{&fuzzer.Properties}
+}
+
+func fuzzMutatorDeps(mctx android.TopDownMutatorContext) {
+ currentModule, ok := mctx.Module().(*Module)
+ if !ok {
+ return
+ }
+
+ if currentModule.fuzzer == nil {
+ return
+ }
+
+ mctx.WalkDeps(func(child android.Module, parent android.Module) bool {
+ c, ok := child.(*Module)
+ if !ok {
+ return false
+ }
+
+ if c.sanitize == nil {
+ return false
+ }
+
+ isFuzzerPointer := c.sanitize.getSanitizerBoolPtr(Fuzzer)
+ if isFuzzerPointer == nil || !*isFuzzerPointer {
+ return false
+ }
+
+ if c.fuzzer == nil {
+ return false
+ }
+
+ c.fuzzer.Properties.FuzzFramework = currentModule.fuzzer.Properties.FuzzFramework
+ return true
+ })
+}
+
// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
// $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on
// your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
-func FuzzFactory() android.Module {
- module := NewFuzz(android.HostAndDeviceSupported)
+func LibFuzzFactory() android.Module {
+ module := NewFuzzer(android.HostAndDeviceSupported)
return module.Init()
}
-func NewFuzzInstaller() *baseInstaller {
- return NewBaseInstaller("fuzz", "fuzz", InstallInData)
-}
-
type fuzzBinary struct {
*binaryDecorator
*baseCompiler
-
- fuzzPackagedModule fuzz.FuzzPackagedModule
-
+ fuzzPackagedModule fuzz.FuzzPackagedModule
installedSharedDeps []string
}
@@ -59,6 +112,7 @@
func (fuzz *fuzzBinary) linkerProps() []interface{} {
props := fuzz.binaryDecorator.linkerProps()
props = append(props, &fuzz.fuzzPackagedModule.FuzzProperties)
+
return props
}
@@ -66,10 +120,14 @@
fuzz.binaryDecorator.linkerInit(ctx)
}
-func (fuzz *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
- deps.StaticLibs = append(deps.StaticLibs,
- config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
- deps = fuzz.binaryDecorator.linkerDeps(ctx, deps)
+func (fuzzBin *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
+ if ctx.Config().Getenv("FUZZ_FRAMEWORK") == "AFL" {
+ deps.HeaderLibs = append(deps.HeaderLibs, "libafl_headers")
+ } else {
+ deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
+ }
+
+ deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
return deps
}
@@ -80,6 +138,7 @@
// target packages.
flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
+
return flags
}
@@ -149,63 +208,65 @@
}
func sharedLibraryInstallLocation(
- libraryPath android.Path, isHost bool, archString string) string {
+ libraryPath android.Path, isHost bool, fuzzDir string, archString string) string {
installLocation := "$(PRODUCT_OUT)/data"
if isHost {
installLocation = "$(HOST_OUT)"
}
installLocation = filepath.Join(
- installLocation, "fuzz", archString, "lib", libraryPath.Base())
+ installLocation, fuzzDir, archString, "lib", libraryPath.Base())
return installLocation
}
// Get the device-only shared library symbols install directory.
-func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, archString string) string {
- return filepath.Join("$(PRODUCT_OUT)/symbols/data/fuzz/", archString, "/lib/", libraryPath.Base())
+func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, fuzzDir string, archString string) string {
+ return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, "/lib/", libraryPath.Base())
}
-func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
- fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
- "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
- fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join(
- "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
- fuzz.binaryDecorator.baseInstaller.install(ctx, file)
+func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
+ installBase := "fuzz"
- fuzz.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzz.fuzzPackagedModule.FuzzProperties.Corpus)
+ fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join(
+ installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
+ fuzzBin.binaryDecorator.baseInstaller.dir64 = filepath.Join(
+ installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
+ fuzzBin.binaryDecorator.baseInstaller.install(ctx, file)
+
+ fuzzBin.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzBin.fuzzPackagedModule.FuzzProperties.Corpus)
builder := android.NewRuleBuilder(pctx, ctx)
intermediateDir := android.PathForModuleOut(ctx, "corpus")
- for _, entry := range fuzz.fuzzPackagedModule.Corpus {
+ for _, entry := range fuzzBin.fuzzPackagedModule.Corpus {
builder.Command().Text("cp").
Input(entry).
Output(intermediateDir.Join(ctx, entry.Base()))
}
builder.Build("copy_corpus", "copy corpus")
- fuzz.fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
+ fuzzBin.fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
- fuzz.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzz.fuzzPackagedModule.FuzzProperties.Data)
+ fuzzBin.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzBin.fuzzPackagedModule.FuzzProperties.Data)
builder = android.NewRuleBuilder(pctx, ctx)
intermediateDir = android.PathForModuleOut(ctx, "data")
- for _, entry := range fuzz.fuzzPackagedModule.Data {
+ for _, entry := range fuzzBin.fuzzPackagedModule.Data {
builder.Command().Text("cp").
Input(entry).
Output(intermediateDir.Join(ctx, entry.Rel()))
}
builder.Build("copy_data", "copy data")
- fuzz.fuzzPackagedModule.DataIntermediateDir = intermediateDir
+ fuzzBin.fuzzPackagedModule.DataIntermediateDir = intermediateDir
- if fuzz.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
- fuzz.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzz.fuzzPackagedModule.FuzzProperties.Dictionary)
- if fuzz.fuzzPackagedModule.Dictionary.Ext() != ".dict" {
+ if fuzzBin.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
+ fuzzBin.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzBin.fuzzPackagedModule.FuzzProperties.Dictionary)
+ if fuzzBin.fuzzPackagedModule.Dictionary.Ext() != ".dict" {
ctx.PropertyErrorf("dictionary",
"Fuzzer dictionary %q does not have '.dict' extension",
- fuzz.fuzzPackagedModule.Dictionary.String())
+ fuzzBin.fuzzPackagedModule.Dictionary.String())
}
}
- if fuzz.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
+ if fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
- android.WriteFileRule(ctx, configPath, fuzz.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
- fuzz.fuzzPackagedModule.Config = configPath
+ android.WriteFileRule(ctx, configPath, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
+ fuzzBin.fuzzPackagedModule.Config = configPath
}
// Grab the list of required shared libraries.
@@ -225,31 +286,34 @@
})
for _, lib := range sharedLibraries {
- fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
+ fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
sharedLibraryInstallLocation(
- lib, ctx.Host(), ctx.Arch().ArchType.String()))
+ lib, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
// Also add the dependency on the shared library symbols dir.
if !ctx.Host() {
- fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
- sharedLibrarySymbolsInstallLocation(lib, ctx.Arch().ArchType.String()))
+ fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
+ sharedLibrarySymbolsInstallLocation(lib, installBase, ctx.Arch().ArchType.String()))
}
}
}
-func NewFuzz(hod android.HostOrDeviceSupported) *Module {
+func NewFuzzer(hod android.HostOrDeviceSupported) *Module {
module, binary := newBinary(hod, false)
+ baseInstallerPath := "fuzz"
- binary.baseInstaller = NewFuzzInstaller()
+ binary.baseInstaller = NewBaseInstaller(baseInstallerPath, baseInstallerPath, InstallInData)
module.sanitize.SetSanitizer(Fuzzer, true)
- fuzz := &fuzzBinary{
+ fuzzBin := &fuzzBinary{
binaryDecorator: binary,
baseCompiler: NewBaseCompiler(),
}
- module.compiler = fuzz
- module.linker = fuzz
- module.installer = fuzz
+ module.compiler = fuzzBin
+ module.linker = fuzzBin
+ module.installer = fuzzBin
+
+ module.fuzzer.Properties.FuzzFramework = fuzz.LibFuzzer
// The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
@@ -266,6 +330,17 @@
disableDarwinAndLinuxBionic.Target.Darwin.Enabled = BoolPtr(false)
disableDarwinAndLinuxBionic.Target.Linux_bionic.Enabled = BoolPtr(false)
ctx.AppendProperties(&disableDarwinAndLinuxBionic)
+
+ targetFramework := fuzz.GetFramework(ctx, fuzz.Cc)
+ if !fuzz.IsValidFrameworkForModule(targetFramework, fuzz.Cc, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzzing_frameworks) {
+ ctx.Module().Disable()
+ return
+ }
+
+ if targetFramework == fuzz.AFL {
+ fuzzBin.baseCompiler.Properties.Srcs = append(fuzzBin.baseCompiler.Properties.Srcs, ":aflpp_driver", ":afl-compiler-rt")
+ module.fuzzer.Properties.FuzzFramework = fuzz.AFL
+ }
})
return module
@@ -275,10 +350,19 @@
// their architecture & target/host specific zip file.
type ccFuzzPackager struct {
fuzz.FuzzPackager
+ fuzzPackagingArchModules string
+ fuzzTargetSharedDepsInstallPairs string
+ allFuzzTargetsName string
}
func fuzzPackagingFactory() android.Singleton {
- return &ccFuzzPackager{}
+
+ fuzzPackager := &ccFuzzPackager{
+ fuzzPackagingArchModules: "SOONG_FUZZ_PACKAGING_ARCH_MODULES",
+ fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
+ allFuzzTargetsName: "ALL_FUZZ_TARGETS",
+ }
+ return fuzzPackager
}
func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
@@ -306,6 +390,7 @@
return
}
+ sharedLibsInstallDirPrefix := "lib"
fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
if !ok {
return
@@ -316,8 +401,15 @@
hostOrTargetString = "host"
}
+ fpm := fuzz.FuzzPackagedModule{}
+ if ok {
+ fpm = fuzzModule.fuzzPackagedModule
+ }
+
+ intermediatePath := "fuzz"
+
archString := ccModule.Arch().ArchType.String()
- archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
+ archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString)
archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
// Grab the list of required shared libraries.
@@ -327,22 +419,21 @@
builder := android.NewRuleBuilder(pctx, ctx)
// Package the corpus, data, dict and config into a zipfile.
- files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder)
+ files = s.PackageArtifacts(ctx, module, fpm, archDir, builder)
// Package shared libraries
- files = append(files, GetSharedLibsToZip(sharedLibraries, ccModule, &s.FuzzPackager, archString, &sharedLibraryInstalled)...)
+ files = append(files, GetSharedLibsToZip(sharedLibraries, ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
// The executable.
files = append(files, fuzz.FileToZip{ccModule.UnstrippedOutputFile(), ""})
- archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
+ archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
if !ok {
return
}
})
s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx)
-
}
func (s *ccFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
@@ -353,27 +444,31 @@
// ready to handle phony targets created in Soong. In the meantime, this
// exports the phony 'fuzz' target and dependencies on packages to
// core/main.mk so that we can use dist-for-goals.
- ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
- ctx.Strict("FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
+
+ ctx.Strict(s.fuzzPackagingArchModules, strings.Join(packages, " "))
+
+ ctx.Strict(s.fuzzTargetSharedDepsInstallPairs,
strings.Join(s.FuzzPackager.SharedLibInstallStrings, " "))
// Preallocate the slice of fuzz targets to minimise memory allocations.
- s.PreallocateSlice(ctx, "ALL_FUZZ_TARGETS")
+ s.PreallocateSlice(ctx, s.allFuzzTargetsName)
}
// GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for
// packaging.
-func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, s *fuzz.FuzzPackager, archString string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
+func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
var files []fuzz.FileToZip
+ fuzzDir := "fuzz"
+
for _, library := range sharedLibraries {
- files = append(files, fuzz.FileToZip{library, "lib"})
+ files = append(files, fuzz.FileToZip{library, destinationPathPrefix})
// For each architecture-specific shared library dependency, we need to
// install it to the output directory. Setup the install destination here,
// which will be used by $(copy-many-files) in the Make backend.
installDestination := sharedLibraryInstallLocation(
- library, module.Host(), archString)
+ library, module.Host(), fuzzDir, archString)
if (*sharedLibraryInstalled)[installDestination] {
continue
}
@@ -391,7 +486,7 @@
// we want symbolization tools (like `stack`) to be able to find the symbols
// in $ANDROID_PRODUCT_OUT/symbols automagically.
if !module.Host() {
- symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, archString)
+ symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, fuzzDir, archString)
symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
library.String()+":"+symbolsInstallDestination)
diff --git a/cc/gen.go b/cc/gen.go
index 8f62363..08b49c9 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -18,6 +18,7 @@
"path/filepath"
"strings"
+ "android/soong/bazel"
"github.com/google/blueprint"
"android/soong/android"
@@ -169,6 +170,41 @@
})
}
+type LexAttrs struct {
+ Srcs bazel.LabelListAttribute
+ Lexopts bazel.StringListAttribute
+}
+
+type LexNames struct {
+ cSrcName bazel.LabelAttribute
+ srcName bazel.LabelAttribute
+}
+
+func bp2BuildLex(ctx android.Bp2buildMutatorContext, moduleName string, ca compilerAttributes) LexNames {
+ names := LexNames{}
+ if !ca.lSrcs.IsEmpty() {
+ names.cSrcName = createLexTargetModule(ctx, moduleName+"_genlex_l", ca.lSrcs, ca.lexopts)
+ }
+ if !ca.llSrcs.IsEmpty() {
+ names.srcName = createLexTargetModule(ctx, moduleName+"_genlex_ll", ca.llSrcs, ca.lexopts)
+ }
+ return names
+}
+
+func createLexTargetModule(ctx android.Bp2buildMutatorContext, name string, srcs bazel.LabelListAttribute, opts bazel.StringListAttribute) bazel.LabelAttribute {
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "genlex",
+ Bzl_load_location: "//build/bazel/rules/cc:flex.bzl",
+ },
+ android.CommonAttributes{Name: name},
+ &LexAttrs{
+ Srcs: srcs,
+ Lexopts: opts,
+ })
+ return bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + name}}
+}
+
func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Paths) {
headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
publicHeaderFile := android.PathForModuleGen(ctx, "sysprop/public", "include", syspropFile.Rel()+".h")
diff --git a/cc/image.go b/cc/image.go
index 3a0857b..921b2bb 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -533,7 +533,7 @@
}
} else {
// This is either in /system (or similar: /data), or is a
- // modules built with the NDK. Modules built with the NDK
+ // module built with the NDK. Modules built with the NDK
// will be restricted using the existing link type checks.
coreVariantNeeded = true
}
diff --git a/cc/library.go b/cc/library.go
index d819c62..897b572 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -110,6 +110,9 @@
// Run checks on all APIs (in addition to the ones referred by
// one of exported ELF symbols.)
Check_all_apis *bool
+
+ // Extra flags passed to header-abi-diff
+ Diff_flags []string
}
// Inject boringssl hash into the shared library. This is only intended for use by external/boringssl.
@@ -397,7 +400,7 @@
if props, ok := props.(*LibraryProperties); ok {
if props.Inject_bssl_hash != nil {
// This is an edge case applies only to libcrypto
- if m.Name() == "libcrypto" {
+ if m.Name() == "libcrypto" || m.Name() == "libcrypto_for_testing" {
sharedTargetAttrs.Inject_bssl_hash.SetSelectValue(axis, config, props.Inject_bssl_hash)
} else {
ctx.PropertyErrorf("inject_bssl_hash", "only applies to libcrypto")
@@ -610,6 +613,9 @@
// Source Abi Diff
sAbiDiff android.OptionalPath
+ // Source Abi Diff against previous SDK version
+ prevSAbiDiff android.OptionalPath
+
// Location of the static library in the sysroot. Empty if the library is
// not included in the NDK.
ndkSysrootPath android.Path
@@ -768,6 +774,12 @@
if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
continue
}
+
+ // Filter out the generated headers from bazel.
+ if strings.HasPrefix(dir, android.PathForBazelOut(ctx, "bazel-out").String()) {
+ continue
+ }
+
// libeigen wrongly exports the root directory "external/eigen". But only two
// subdirectories "Eigen" and "unsupported" contain exported header files. Even worse
// some of them have no extension. So we need special treatment for libeigen in order
@@ -922,7 +934,6 @@
if ctx.Darwin() {
f = append(f,
"-dynamiclib",
- "-single_module",
"-install_name @rpath/"+libName+flags.Toolchain.ShlibSuffix(),
)
if ctx.Arch().ArchType == android.X86 {
@@ -1030,9 +1041,19 @@
ctx.PropertyErrorf("symbol_file", "%q doesn't have .map.txt suffix", symbolFile)
return Objects{}
}
+ // b/239274367 --apex and --systemapi filters symbols tagged with # apex and #
+ // systemapi, respectively. The former is for symbols defined in platform libraries
+ // and the latter is for symbols defined in APEXes.
+ var flag string
+ if ctx.Module().(android.ApexModule).NotInPlatform() {
+ flag = "--apex"
+ } else {
+ // TODO(b/239274367) drop --apex when #apex is replaced with #systemapi
+ // in the map.txt files of platform libraries
+ flag = "--systemapi --apex"
+ }
nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile,
- android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion),
- "--apex")
+ android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
library.versionScriptPath = android.OptionalPathForPath(
nativeAbiResult.versionScript)
@@ -1582,10 +1603,10 @@
func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
// The logic must be consistent with classifySourceAbiDump.
isNdk := ctx.isNdk(ctx.Config())
- isLlndkOrVndk := ctx.IsLlndkPublic() || (ctx.useVndk() && ctx.isVndk())
+ isVndk := ctx.useVndk() && ctx.isVndk()
- refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, false)
- refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, true)
+ refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isVndk, false)
+ refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isVndk, true)
if refAbiDumpTextFile.Valid() {
if refAbiDumpGzipFile.Valid() {
@@ -1602,16 +1623,51 @@
return nil
}
+func prevDumpRefVersion(ctx ModuleContext) string {
+ sdkVersionInt := ctx.Config().PlatformSdkVersion().FinalInt()
+ sdkVersionStr := ctx.Config().PlatformSdkVersion().String()
+
+ if ctx.Config().PlatformSdkFinal() {
+ return strconv.Itoa(sdkVersionInt - 1)
+ } else {
+ var dirName string
+
+ isNdk := ctx.isNdk(ctx.Config())
+ if isNdk {
+ dirName = "ndk"
+ } else {
+ dirName = "platform"
+ }
+
+ // The platform SDK version can be upgraded before finalization while the corresponding abi dumps hasn't
+ // been generated. Thus the Cross-Version Check chooses PLATFORM_SDK_VERION - 1 as previous version.
+ // This situation could be identified by checking the existence of the PLATFORM_SDK_VERION dump directory.
+ refDumpDir := android.ExistentPathForSource(ctx, "prebuilts", "abi-dumps", dirName, sdkVersionStr)
+ if refDumpDir.Valid() {
+ return sdkVersionStr
+ } else {
+ return strconv.Itoa(sdkVersionInt - 1)
+ }
+ }
+}
+
func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
if library.sabi.shouldCreateSourceAbiDump() {
- var vndkVersion string
+ var version string
+ var prevVersion string
if ctx.useVndk() {
// For modules linking against vndk, follow its vndk version
- vndkVersion = ctx.Module().(*Module).VndkVersion()
+ version = ctx.Module().(*Module).VndkVersion()
} else {
- // Regard the other modules as PLATFORM_VNDK_VERSION
- vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
+ // After sdk finalizatoin, the ABI of the latest API level must be consistent with the source code
+ // so the chosen reference dump is the PLATFORM_SDK_VERSION.
+ if ctx.Config().PlatformSdkFinal() {
+ version = ctx.Config().PlatformSdkVersion().String()
+ } else {
+ version = "current"
+ }
+ prevVersion = prevDumpRefVersion(ctx)
}
exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
@@ -1630,12 +1686,24 @@
addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
- refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName)
+ if prevVersion != "" {
+ prevRefAbiDumpFile := getRefAbiDumpFile(ctx, prevVersion, fileName)
+ if prevRefAbiDumpFile != nil {
+ library.prevSAbiDiff = sourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
+ prevRefAbiDumpFile, fileName, prevVersion, exportedHeaderFlags,
+ library.Properties.Header_abi_checker.Diff_flags,
+ Bool(library.Properties.Header_abi_checker.Check_all_apis),
+ ctx.IsLlndk(), ctx.isNdk(ctx.Config()), ctx.IsVndkExt(), true)
+ }
+ }
+
+ refAbiDumpFile := getRefAbiDumpFile(ctx, version, fileName)
if refAbiDumpFile != nil {
library.sAbiDiff = sourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
- refAbiDumpFile, fileName, exportedHeaderFlags,
+ refAbiDumpFile, fileName, "", exportedHeaderFlags,
+ library.Properties.Header_abi_checker.Diff_flags,
Bool(library.Properties.Header_abi_checker.Check_all_apis),
- ctx.IsLlndk(), ctx.isNdk(ctx.Config()), ctx.IsVndkExt())
+ ctx.IsLlndk(), ctx.isNdk(ctx.Config()), ctx.IsVndkExt(), false)
}
}
}
@@ -2432,7 +2500,6 @@
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
BuiltTool("bssl_inject_hash").
- Flag("-sha256").
FlagWithInput("-in-object ", outputFile).
FlagWithOutput("-o ", hashedOutputfile)
rule.Build("injectCryptoHash", "inject crypto hash")
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 7232290..970d8d1 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -125,12 +125,12 @@
baseAttributes := bp2BuildParseBaseProps(ctx, module)
exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, &baseAttributes.includes)
linkerAttrs := baseAttributes.linkerAttributes
+ (&linkerAttrs.deps).Append(linkerAttrs.dynamicDeps)
attrs := &bazelCcLibraryHeadersAttributes{
Export_includes: exportedIncludes.Includes,
Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
Export_system_includes: exportedIncludes.SystemIncludes,
- Implementation_deps: linkerAttrs.implementationDeps,
Deps: linkerAttrs.deps,
System_dynamic_deps: linkerAttrs.systemDynamicDeps,
Hdrs: baseAttributes.hdrs,
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 4d0148d..14d1b96 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -17,6 +17,7 @@
import (
"android/soong/android"
"android/soong/multitree"
+ "strings"
)
func init() {
@@ -25,10 +26,96 @@
func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) {
// cc_api_stub_library shares a lot of ndk_library, and this will be refactored later
+ ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory)
ctx.RegisterModuleType("cc_api_stub_library", CcApiStubLibraryFactory)
ctx.RegisterModuleType("cc_api_contribution", CcApiContributionFactory)
}
+// 'cc_api_library' is a module type which is from the exported API surface
+// with C shared library type. The module will replace original module, and
+// offer a link to the module that generates shared library object from the
+// map file.
+type apiLibraryProperties struct {
+ Src *string `android:"arch_variant"`
+}
+
+type apiLibraryDecorator struct {
+ *libraryDecorator
+ properties apiLibraryProperties
+}
+
+func CcApiLibraryFactory() android.Module {
+ module, decorator := NewLibrary(android.DeviceSupported)
+ apiLibraryDecorator := &apiLibraryDecorator{
+ libraryDecorator: decorator,
+ }
+ apiLibraryDecorator.BuildOnlyShared()
+
+ module.stl = nil
+ module.sanitize = nil
+ decorator.disableStripping()
+
+ module.compiler = nil
+ module.linker = apiLibraryDecorator
+ module.installer = nil
+ module.AddProperties(&module.Properties, &apiLibraryDecorator.properties)
+
+ // Mark module as stub, so APEX would not include this stub in the package.
+ module.library.setBuildStubs(true)
+
+ // Prevent default system libs (libc, libm, and libdl) from being linked
+ if apiLibraryDecorator.baseLinker.Properties.System_shared_libs == nil {
+ apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{}
+ }
+
+ module.Init()
+
+ return module
+}
+
+func (d *apiLibraryDecorator) Name(basename string) string {
+ return basename + multitree.GetApiImportSuffix()
+}
+
+func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
+ // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
+ d.libraryDecorator.flagExporter.exportIncludes(ctx)
+ d.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
+ d.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
+ d.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
+ d.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
+ d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+ d.libraryDecorator.flagExporter.setProvider(ctx)
+
+ in := android.PathForModuleSrc(ctx, *d.properties.Src)
+
+ d.unstrippedOutputFile = in
+ libName := d.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
+
+ tocFile := android.PathForModuleOut(ctx, libName+".toc")
+ d.tocFile = android.OptionalPathForPath(tocFile)
+ TransformSharedObjectToToc(ctx, in, tocFile)
+
+ ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+ SharedLibrary: in,
+ Target: ctx.Target(),
+
+ TableOfContents: d.tocFile,
+ })
+
+ return in
+}
+
+func (d *apiLibraryDecorator) availableFor(what string) bool {
+ // Stub from API surface should be available for any APEX.
+ return true
+}
+
+func (d *apiLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+ d.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), multitree.GetApiImportSuffix())
+ return d.libraryDecorator.linkerFlags(ctx, flags)
+}
+
func CcApiStubLibraryFactory() android.Module {
module, decorator := NewLibrary(android.DeviceSupported)
apiStubDecorator := &apiStubDecorator{
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
index 15b56d2..c2ac941 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -22,6 +22,8 @@
"android/soong/android"
"android/soong/multitree"
+
+ "github.com/google/blueprint"
)
func TestCcApiStubLibraryOutputFiles(t *testing.T) {
@@ -106,3 +108,111 @@
android.AssertStringEquals(t, "name", "foo.mysdk", api_surface_gen_rule_args["name"])
android.AssertStringEquals(t, "symbol_file", "foo.map.txt", api_surface_gen_rule_args["symbol_file"])*/
}
+
+func hasDirectDependency(t *testing.T, ctx *android.TestResult, from android.Module, to android.Module) bool {
+ t.Helper()
+ var found bool
+ ctx.VisitDirectDeps(from, func(dep blueprint.Module) {
+ if dep == to {
+ found = true
+ }
+ })
+ return found
+}
+
+func TestApiLibraryReplacesExistingModule(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar"],
+ }
+
+ cc_library {
+ name: "libbar",
+ }
+
+ cc_api_library {
+ name: "libbar",
+ src: "libbar.so",
+ }
+
+ api_imports {
+ name: "api_imports",
+ shared_libs: [
+ "libbar",
+ ],
+ header_libs: [],
+ }
+ `
+
+ ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+ libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
+ libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+ android.AssertBoolEquals(t, "original library should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbar))
+ android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+}
+
+func TestApiLibraryDoNotRequireOriginalModule(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar"],
+ }
+
+ cc_api_library {
+ name: "libbar",
+ src: "libbar.so",
+ }
+
+ api_imports {
+ name: "api_imports",
+ shared_libs: [
+ "libbar",
+ ],
+ header_libs: [],
+ }
+ `
+
+ ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+ libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+ android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+}
+
+func TestApiLibraryShouldNotReplaceWithoutApiImport(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libfoo",
+ shared_libs: ["libbar"],
+ }
+
+ cc_library {
+ name: "libbar",
+ }
+
+ cc_api_library {
+ name: "libbar",
+ src: "libbar.so",
+ }
+
+ api_imports {
+ name: "api_imports",
+ shared_libs: [],
+ header_libs: [],
+ }
+ `
+
+ ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+ libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
+ libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+ android.AssertBoolEquals(t, "original library should be linked", true, hasDirectDependency(t, ctx, libfoo, libbar))
+ android.AssertBoolEquals(t, "Stub library from API surface should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+}
diff --git a/cc/linkable.go b/cc/linkable.go
index 04eab39..2316d86 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -22,13 +22,6 @@
// than left undefined.
IsSanitizerExplicitlyDisabled(t SanitizerType) bool
- // SanitizeDep returns true if the module is statically linked into another that is sanitized
- // with the given sanitizer.
- SanitizeDep(t SanitizerType) bool
-
- // SetSanitizeDep marks a module as a static dependency of another module to be sanitized.
- SetSanitizeDep(t SanitizerType)
-
// SetSanitizer enables or disables the specified sanitizer type if it's supported, otherwise this should panic.
SetSanitizer(t SanitizerType, b bool)
@@ -113,6 +106,9 @@
UnstrippedOutputFile() android.Path
CoverageFiles() android.Paths
+ // CoverageOutputFile returns the output archive of gcno coverage information files.
+ CoverageOutputFile() android.OptionalPath
+
NonCcVariants() bool
SelectedStl() string
@@ -140,6 +136,12 @@
UseSdk() bool
+ // IsNdk returns true if the library is in the configs known NDK list.
+ IsNdk(config android.Config) bool
+
+ // IsStubs returns true if the this is a stubs library.
+ IsStubs() bool
+
// IsLlndk returns true for both LLNDK (public) and LLNDK-private libs.
IsLlndk() bool
diff --git a/cc/linker.go b/cc/linker.go
index 4e9404c..76a60ca 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -399,7 +399,7 @@
if ctx.toolchain().Bionic() {
// libclang_rt.builtins has to be last on the command line
if !Bool(linker.Properties.No_libcrt) && !ctx.header() {
- deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
+ deps.UnexportedStaticLibs = append(deps.UnexportedStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
}
if inList("libdl", deps.SharedLibs) {
@@ -422,7 +422,7 @@
}
} else if ctx.toolchain().Musl() {
if !Bool(linker.Properties.No_libcrt) && !ctx.header() {
- deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
+ deps.UnexportedStaticLibs = append(deps.UnexportedStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
}
}
@@ -436,11 +436,6 @@
}
func (linker *baseLinker) useClangLld(ctx ModuleContext) bool {
- // Clang lld is not ready for for Darwin host executables yet.
- // See https://lld.llvm.org/AtomLLD.html for status of lld for Mach-O.
- if ctx.Darwin() {
- return false
- }
if linker.Properties.Use_clang_lld != nil {
return Bool(linker.Properties.Use_clang_lld)
}
@@ -530,10 +525,6 @@
}
}
- if ctx.toolchain().LibclangRuntimeLibraryArch() != "" {
- flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--exclude-libs="+config.BuiltinsRuntimeLibrary(ctx.toolchain())+".a")
- }
-
CheckBadLinkerFlags(ctx, "ldflags", linker.Properties.Ldflags)
flags.Local.LdFlags = append(flags.Local.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
diff --git a/cc/ndk_api_coverage_parser/__init__.py b/cc/ndk_api_coverage_parser/__init__.py
index 8b9cd66..752f7d4 100755
--- a/cc/ndk_api_coverage_parser/__init__.py
+++ b/cc/ndk_api_coverage_parser/__init__.py
@@ -23,6 +23,7 @@
from xml.etree.ElementTree import Element, SubElement, tostring
from symbolfile import (
ALL_ARCHITECTURES,
+ Filter,
FUTURE_API_LEVEL,
MultiplyDefinedSymbolError,
SymbolFileParser,
@@ -139,9 +140,8 @@
with open(args.symbol_file) as symbol_file:
try:
- versions = SymbolFileParser(
- symbol_file, api_map, "", FUTURE_API_LEVEL, True, True
- ).parse()
+ filt = Filter("", FUTURE_API_LEVEL, True, True, True)
+ versions = SymbolFileParser(symbol_file, api_map, filt).parse()
except MultiplyDefinedSymbolError as ex:
sys.exit('{}: error: {}'.format(args.symbol_file, ex))
diff --git a/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py b/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py
index 141059c..7c6ef68 100644
--- a/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py
+++ b/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py
@@ -20,7 +20,7 @@
import unittest
from xml.etree.ElementTree import fromstring
-from symbolfile import FUTURE_API_LEVEL, SymbolFileParser
+from symbolfile import Filter, FUTURE_API_LEVEL, SymbolFileParser
import ndk_api_coverage_parser as nparser
@@ -78,9 +78,8 @@
"""
)
)
- parser = SymbolFileParser(
- input_file, {}, "", FUTURE_API_LEVEL, True, True
- )
+ filt = Filter("", FUTURE_API_LEVEL, True, True, True)
+ parser = SymbolFileParser(input_file, {}, filt)
generator = nparser.XmlGenerator(io.StringIO())
result = generator.convertToXml(parser.parse())
expected = fromstring(
diff --git a/cc/ndkstubgen/__init__.py b/cc/ndkstubgen/__init__.py
index 5e6b8f5..f893d41 100755
--- a/cc/ndkstubgen/__init__.py
+++ b/cc/ndkstubgen/__init__.py
@@ -29,15 +29,12 @@
class Generator:
"""Output generator that writes stub source files and version scripts."""
def __init__(self, src_file: TextIO, version_script: TextIO,
- symbol_list: TextIO, arch: Arch, api: int, llndk: bool,
- apex: bool) -> None:
+ symbol_list: TextIO, filt: symbolfile.Filter) -> None:
self.src_file = src_file
self.version_script = version_script
self.symbol_list = symbol_list
- self.arch = arch
- self.api = api
- self.llndk = llndk
- self.apex = apex
+ self.filter = filt
+ self.api = filt.api
def write(self, versions: Iterable[Version]) -> None:
"""Writes all symbol data to the output files."""
@@ -47,8 +44,7 @@
def write_version(self, version: Version) -> None:
"""Writes a single version block's data to the output files."""
- if symbolfile.should_omit_version(version, self.arch, self.api,
- self.llndk, self.apex):
+ if self.filter.should_omit_version(version):
return
section_versioned = symbolfile.symbol_versioned_in_api(
@@ -56,8 +52,7 @@
version_empty = True
pruned_symbols = []
for symbol in version.symbols:
- if symbolfile.should_omit_symbol(symbol, self.arch, self.api,
- self.llndk, self.apex):
+ if self.filter.should_omit_symbol(symbol):
continue
if symbolfile.symbol_versioned_in_api(symbol.tags, self.api):
@@ -110,12 +105,12 @@
parser.add_argument(
'--apex',
action='store_true',
- help='Use the APEX variant. Note: equivalent to --system-api.')
+ help='Use the APEX variant.')
parser.add_argument(
- '--system-api',
+ '--systemapi',
action='store_true',
- dest='apex',
- help='Use the SystemAPI variant. Note: equivalent to --apex.')
+ dest='systemapi',
+ help='Use the SystemAPI variant.')
parser.add_argument('--api-map',
type=resolved_path,
@@ -152,11 +147,10 @@
verbosity = 2
logging.basicConfig(level=verbose_map[verbosity])
+ filt = symbolfile.Filter(args.arch, api, args.llndk, args.apex, args.systemapi)
with args.symbol_file.open() as symbol_file:
try:
- versions = symbolfile.SymbolFileParser(symbol_file, api_map,
- args.arch, api, args.llndk,
- args.apex).parse()
+ versions = symbolfile.SymbolFileParser(symbol_file, api_map, filt).parse()
except symbolfile.MultiplyDefinedSymbolError as ex:
sys.exit(f'{args.symbol_file}: error: {ex}')
@@ -164,7 +158,7 @@
with args.version_script.open('w') as version_script:
with args.symbol_list.open('w') as symbol_list:
generator = Generator(src_file, version_script, symbol_list,
- args.arch, api, args.llndk, args.apex)
+ filt)
generator.write(versions)
diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py
index c8cd056..450719b 100755
--- a/cc/ndkstubgen/test_ndkstubgen.py
+++ b/cc/ndkstubgen/test_ndkstubgen.py
@@ -18,6 +18,7 @@
import io
import textwrap
import unittest
+from copy import copy
import symbolfile
from symbolfile import Arch, Tags
@@ -29,6 +30,9 @@
class GeneratorTest(unittest.TestCase):
+ def setUp(self) -> None:
+ self.filter = symbolfile.Filter(Arch('arm'), 9, False, False)
+
def test_omit_version(self) -> None:
# Thorough testing of the cases involved here is handled by
# OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest.
@@ -37,7 +41,7 @@
symbol_list_file = io.StringIO()
generator = ndkstubgen.Generator(src_file,
version_file, symbol_list_file,
- Arch('arm'), 9, False, False)
+ self.filter)
version = symbolfile.Version('VERSION_PRIVATE', None, Tags(), [
symbolfile.Symbol('foo', Tags()),
@@ -70,7 +74,7 @@
symbol_list_file = io.StringIO()
generator = ndkstubgen.Generator(src_file,
version_file, symbol_list_file,
- Arch('arm'), 9, False, False)
+ self.filter)
version = symbolfile.Version('VERSION_1', None, Tags(), [
symbolfile.Symbol('foo', Tags.from_strs(['x86'])),
@@ -106,7 +110,7 @@
symbol_list_file = io.StringIO()
generator = ndkstubgen.Generator(src_file,
version_file, symbol_list_file,
- Arch('arm'), 9, False, False)
+ self.filter)
versions = [
symbolfile.Version('VERSION_1', None, Tags(), [
@@ -162,6 +166,9 @@
class IntegrationTest(unittest.TestCase):
+ def setUp(self) -> None:
+ self.filter = symbolfile.Filter(Arch('arm'), 9, False, False)
+
def test_integration(self) -> None:
api_map = {
'O': 9000,
@@ -199,8 +206,7 @@
wobble;
} VERSION_4;
"""))
- parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'),
- 9, False, False)
+ parser = symbolfile.SymbolFileParser(input_file, api_map, self.filter)
versions = parser.parse()
src_file = io.StringIO()
@@ -208,7 +214,7 @@
symbol_list_file = io.StringIO()
generator = ndkstubgen.Generator(src_file,
version_file, symbol_list_file,
- Arch('arm'), 9, False, False)
+ self.filter)
generator.write(versions)
expected_src = textwrap.dedent("""\
@@ -263,16 +269,18 @@
*;
};
"""))
- parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'),
- 9001, False, False)
+ f = copy(self.filter)
+ f.api = 9001
+ parser = symbolfile.SymbolFileParser(input_file, api_map, f)
versions = parser.parse()
src_file = io.StringIO()
version_file = io.StringIO()
symbol_list_file = io.StringIO()
+ f = copy(self.filter)
+ f.api = 9001
generator = ndkstubgen.Generator(src_file,
- version_file, symbol_list_file,
- Arch('arm'), 9001, False, False)
+ version_file, symbol_list_file, f)
generator.write(versions)
expected_src = textwrap.dedent("""\
@@ -322,8 +330,9 @@
} VERSION_2;
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, False)
+ f = copy(self.filter)
+ f.api = 16
+ parser = symbolfile.SymbolFileParser(input_file, {}, f)
with self.assertRaises(
symbolfile.MultiplyDefinedSymbolError) as ex_context:
@@ -370,16 +379,18 @@
wobble;
} VERSION_4;
"""))
- parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'),
- 9, False, True)
+ f = copy(self.filter)
+ f.apex = True
+ parser = symbolfile.SymbolFileParser(input_file, api_map, f)
versions = parser.parse()
src_file = io.StringIO()
version_file = io.StringIO()
symbol_list_file = io.StringIO()
+ f = copy(self.filter)
+ f.apex = True
generator = ndkstubgen.Generator(src_file,
- version_file, symbol_list_file,
- Arch('arm'), 9, False, True)
+ version_file, symbol_list_file, f)
generator.write(versions)
expected_src = textwrap.dedent("""\
@@ -428,20 +439,19 @@
*;
};
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'),
- 9, llndk=False, apex=True)
+ f = copy(self.filter)
+ f.apex = True
+ parser = symbolfile.SymbolFileParser(input_file, {}, f)
versions = parser.parse()
src_file = io.StringIO()
version_file = io.StringIO()
symbol_list_file = io.StringIO()
+ f = copy(self.filter)
+ f.apex = True
generator = ndkstubgen.Generator(src_file,
version_file,
- symbol_list_file,
- Arch('arm'),
- 9,
- llndk=False,
- apex=True)
+ symbol_list_file, f)
generator.write(versions)
self.assertEqual('', src_file.getvalue())
diff --git a/cc/pgo.go b/cc/pgo.go
index 0632c15..463e2e6 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -41,7 +41,6 @@
const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
const profileUseInstrumentFormat = "-fprofile-use=%s"
-const profileUseSamplingFormat = "-fprofile-sample-accurate -fprofile-sample-use=%s"
func getPgoProfileProjects(config android.DeviceConfig) []string {
return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
@@ -56,12 +55,11 @@
type PgoProperties struct {
Pgo struct {
Instrumentation *bool
- Sampling *bool `android:"arch_variant"`
Profile_file *string `android:"arch_variant"`
Benchmarks []string
Enable_profile_use *bool `android:"arch_variant"`
// Additional compiler flags to use when building this module
- // for profiling (either instrumentation or sampling).
+ // for profiling.
Cflags []string `android:"arch_variant"`
} `android:"arch_variant"`
@@ -79,10 +77,6 @@
return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
}
-func (props *PgoProperties) isSampling() bool {
- return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true
-}
-
func (pgo *pgo) props() []interface{} {
return []interface{}{&pgo.Properties}
}
@@ -135,18 +129,8 @@
return android.OptionalPathForPath(nil)
}
-func (props *PgoProperties) profileUseFlag(ctx ModuleContext, file string) string {
- if props.isInstrumentation() {
- return fmt.Sprintf(profileUseInstrumentFormat, file)
- }
- if props.isSampling() {
- return fmt.Sprintf(profileUseSamplingFormat, file)
- }
- return ""
-}
-
func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
- flags := []string{props.profileUseFlag(ctx, file)}
+ flags := []string{fmt.Sprintf(profileUseInstrumentFormat, file)}
flags = append(flags, profileUseOtherFlags...)
return flags
}
@@ -169,19 +153,14 @@
// if profileFile gets updated
flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
-
- if props.isSampling() {
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
- }
}
return flags
}
func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
isInstrumentation := props.isInstrumentation()
- isSampling := props.isSampling()
- profileKindPresent := isInstrumentation || isSampling
+ profileKindPresent := isInstrumentation
filePresent := props.Pgo.Profile_file != nil
benchmarksPresent := len(props.Pgo.Benchmarks) > 0
@@ -194,7 +173,7 @@
if !profileKindPresent || !filePresent {
var missing []string
if !profileKindPresent {
- missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
+ missing = append(missing, "profile kind")
}
if !filePresent {
missing = append(missing, "profile_file property")
@@ -208,14 +187,6 @@
ctx.ModuleErrorf("Instrumentation PGO specification is missing benchmark property")
}
- if isSampling {
- ctx.ModuleErrorf("Sampling PGO is deprecated, use AFDO instead")
- }
-
- if isSampling && isInstrumentation {
- ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set")
- }
-
return true
}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index a29e618..8c404d3 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -55,6 +55,13 @@
// This is needed only if this library is linked by other modules in build time.
// Only makes sense for the Windows target.
Windows_import_lib *string `android:"path,arch_variant"`
+
+ // MixedBuildsDisabled is true if and only if building this prebuilt is explicitly disabled in mixed builds for either
+ // its static or shared version on the current build variant. This is to prevent Bazel targets for build variants with
+ // which either the static or shared version is incompatible from participating in mixed buiods. Please note that this
+ // is an override and does not fully determine whether Bazel or Soong will be used. For the full determination, see
+ // cc.ProcessBazelQueryResponse, cc.QueueBazelCall, and cc.MixedBuildsDisabled.
+ MixedBuildsDisabled bool `blueprint:"mutated"`
}
type prebuiltLinker struct {
@@ -244,6 +251,7 @@
func (p *prebuiltLibraryLinker) disablePrebuilt() {
p.properties.Srcs = nil
+ p.properties.MixedBuildsDisabled = true
}
// Implements versionedInterface
@@ -255,6 +263,7 @@
module, library := NewLibrary(hod)
module.compiler = nil
module.bazelable = true
+ module.bazelHandler = &prebuiltLibraryBazelHandler{module: module, library: library}
prebuilt := &prebuiltLibraryLinker{
libraryDecorator: library,
@@ -310,8 +319,6 @@
func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
module, library := NewPrebuiltLibrary(hod, "srcs")
library.BuildOnlyShared()
- module.bazelable = true
- module.bazelHandler = &prebuiltSharedLibraryBazelHandler{module: module, library: library}
// Prebuilt shared libraries can be included in APEXes
android.InitApexModule(module)
@@ -329,8 +336,7 @@
func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
module, library := NewPrebuiltLibrary(hod, "srcs")
library.BuildOnlyStatic()
- module.bazelable = true
- module.bazelHandler = &prebuiltStaticLibraryBazelHandler{module: module, library: library}
+
return module, library
}
@@ -406,29 +412,52 @@
properties prebuiltObjectProperties
}
-type prebuiltStaticLibraryBazelHandler struct {
+type prebuiltLibraryBazelHandler struct {
module *Module
library *libraryDecorator
}
-var _ BazelHandler = (*prebuiltStaticLibraryBazelHandler)(nil)
+var _ BazelHandler = (*prebuiltLibraryBazelHandler)(nil)
-func (h *prebuiltStaticLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
+func (h *prebuiltLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
+ if h.module.linker.(*prebuiltLibraryLinker).properties.MixedBuildsDisabled {
+ return
+ }
bazelCtx := ctx.Config().BazelContext
bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKey(ctx))
}
-func (h *prebuiltStaticLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
+func (h *prebuiltLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
+ if h.module.linker.(*prebuiltLibraryLinker).properties.MixedBuildsDisabled {
+ return
+ }
bazelCtx := ctx.Config().BazelContext
ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
if err != nil {
ctx.ModuleErrorf(err.Error())
return
}
+
+ if h.module.static() {
+ if ok := h.processStaticBazelQueryResponse(ctx, label, ccInfo); !ok {
+ return
+ }
+ } else if h.module.Shared() {
+ if ok := h.processSharedBazelQueryResponse(ctx, label, ccInfo); !ok {
+ return
+ }
+ } else {
+ return
+ }
+
+ h.module.maybeUnhideFromMake()
+}
+
+func (h *prebuiltLibraryBazelHandler) processStaticBazelQueryResponse(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) bool {
staticLibs := ccInfo.CcStaticLibraryFiles
if len(staticLibs) > 1 {
ctx.ModuleErrorf("expected 1 static library from bazel target %q, got %s", label, staticLibs)
- return
+ return false
}
// TODO(b/184543518): cc_prebuilt_library_static may have properties for re-exporting flags
@@ -443,7 +472,7 @@
if len(staticLibs) == 0 {
h.module.outputFile = android.OptionalPath{}
- return
+ return true
}
out := android.PathForBazelOut(ctx, staticLibs[0])
@@ -455,31 +484,15 @@
TransitiveStaticLibrariesForOrdering: depSet,
})
+
+ return true
}
-type prebuiltSharedLibraryBazelHandler struct {
- module *Module
- library *libraryDecorator
-}
-
-var _ BazelHandler = (*prebuiltSharedLibraryBazelHandler)(nil)
-
-func (h *prebuiltSharedLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
- bazelCtx := ctx.Config().BazelContext
- bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKey(ctx))
-}
-
-func (h *prebuiltSharedLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
- bazelCtx := ctx.Config().BazelContext
- ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
- if err != nil {
- ctx.ModuleErrorf(err.Error())
- return
- }
+func (h *prebuiltLibraryBazelHandler) processSharedBazelQueryResponse(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) bool {
sharedLibs := ccInfo.CcSharedLibraryFiles
- if len(sharedLibs) != 1 {
+ if len(sharedLibs) > 1 {
ctx.ModuleErrorf("expected 1 shared library from bazel target %s, got %q", label, sharedLibs)
- return
+ return false
}
// TODO(b/184543518): cc_prebuilt_library_shared may have properties for re-exporting flags
@@ -487,14 +500,9 @@
// TODO(eakammer):Add stub-related flags if this library is a stub library.
// h.library.exportVersioningMacroIfNeeded(ctx)
- // Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise
- // validation will fail. For now, set this to an empty list.
- // TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation.
- h.library.collectedSnapshotHeaders = android.Paths{}
-
if len(sharedLibs) == 0 {
h.module.outputFile = android.OptionalPath{}
- return
+ return true
}
out := android.PathForBazelOut(ctx, sharedLibs[0])
@@ -519,6 +527,7 @@
h.library.setFlagExporterInfoFromCcInfo(ctx, ccInfo)
h.module.maybeUnhideFromMake()
+ return true
}
func (p *prebuiltObjectLinker) prebuilt() *android.Prebuilt {
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 901f458..e959157 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -381,6 +381,149 @@
assertString(t, static2.OutputFile().Path().Base(), "libf.hwasan.a")
}
+func TestPrebuiltLibraryWithBazel(t *testing.T) {
+ const bp = `
+cc_prebuilt_library {
+ name: "foo",
+ shared: {
+ srcs: ["foo.so"],
+ },
+ static: {
+ srcs: ["foo.a"],
+ },
+ bazel_module: { label: "//foo/bar:bar" },
+}`
+ outBaseDir := "outputbase"
+ result := android.GroupFixturePreparers(
+ prepareForPrebuiltTest,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: outBaseDir,
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//foo/bar:bar": cquery.CcInfo{
+ CcSharedLibraryFiles: []string{"foo.so"},
+ },
+ "//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
+ CcStaticLibraryFiles: []string{"foo.a"},
+ },
+ },
+ }
+ }),
+ ).RunTestWithBp(t, bp)
+ sharedFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
+ pathPrefix := outBaseDir + "/execroot/__main__/"
+
+ sharedInfo := result.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo)
+ android.AssertPathRelativeToTopEquals(t,
+ "prebuilt library shared target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
+ pathPrefix+"foo.so", sharedInfo.SharedLibrary)
+
+ outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+ expectedOutputFiles := []string{pathPrefix + "foo.so"}
+ android.AssertDeepEquals(t,
+ "prebuilt library shared target output files did not match expected.",
+ expectedOutputFiles, outputFiles.Strings())
+
+ staticFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
+ staticInfo := result.ModuleProvider(staticFoo, StaticLibraryInfoProvider).(StaticLibraryInfo)
+ android.AssertPathRelativeToTopEquals(t,
+ "prebuilt library static target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
+ pathPrefix+"foo.a", staticInfo.StaticLibrary)
+
+ staticOutputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object staticOutputFiles %s", err)
+ }
+ expectedStaticOutputFiles := []string{pathPrefix + "foo.a"}
+ android.AssertDeepEquals(t,
+ "prebuilt library static target output files did not match expected.",
+ expectedStaticOutputFiles, staticOutputFiles.Strings())
+}
+
+func TestPrebuiltLibraryWithBazelStaticDisabled(t *testing.T) {
+ const bp = `
+cc_prebuilt_library {
+ name: "foo",
+ shared: {
+ srcs: ["foo.so"],
+ },
+ static: {
+ enabled: false
+ },
+ bazel_module: { label: "//foo/bar:bar" },
+}`
+ outBaseDir := "outputbase"
+ result := android.GroupFixturePreparers(
+ prepareForPrebuiltTest,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: outBaseDir,
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//foo/bar:bar": cquery.CcInfo{
+ CcSharedLibraryFiles: []string{"foo.so"},
+ },
+ },
+ }
+ }),
+ ).RunTestWithBp(t, bp)
+ sharedFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
+ pathPrefix := outBaseDir + "/execroot/__main__/"
+
+ sharedInfo := result.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo)
+ android.AssertPathRelativeToTopEquals(t,
+ "prebuilt library shared target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
+ pathPrefix+"foo.so", sharedInfo.SharedLibrary)
+
+ outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+ expectedOutputFiles := []string{pathPrefix + "foo.so"}
+ android.AssertDeepEquals(t,
+ "prebuilt library shared target output files did not match expected.",
+ expectedOutputFiles, outputFiles.Strings())
+}
+
+func TestPrebuiltLibraryStaticWithBazel(t *testing.T) {
+ const bp = `
+cc_prebuilt_library_static {
+ name: "foo",
+ srcs: ["foo.so"],
+ bazel_module: { label: "//foo/bar:bar" },
+}`
+ outBaseDir := "outputbase"
+ result := android.GroupFixturePreparers(
+ prepareForPrebuiltTest,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: outBaseDir,
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//foo/bar:bar": cquery.CcInfo{
+ CcStaticLibraryFiles: []string{"foo.so"},
+ },
+ },
+ }
+ }),
+ ).RunTestWithBp(t, bp)
+ staticFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
+ pathPrefix := outBaseDir + "/execroot/__main__/"
+
+ info := result.ModuleProvider(staticFoo, StaticLibraryInfoProvider).(StaticLibraryInfo)
+ android.AssertPathRelativeToTopEquals(t,
+ "prebuilt library static path did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
+ pathPrefix+"foo.so", info.StaticLibrary)
+
+ outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+ expectedOutputFiles := []string{pathPrefix + "foo.so"}
+ android.AssertDeepEquals(t, "prebuilt library static output files did not match expected.", expectedOutputFiles, outputFiles.Strings())
+}
+
func TestPrebuiltLibrarySharedWithBazelWithoutToc(t *testing.T) {
const bp = `
cc_prebuilt_library_shared {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 42a112e..86472a2 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -153,9 +153,10 @@
func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) {
switch t {
- case Asan, Hwasan, Fuzzer, scs, tsan, cfi:
- ctx.TopDown(t.variationName()+"_deps", sanitizerDepsMutator(t))
- ctx.BottomUp(t.variationName(), sanitizerMutator(t))
+ case cfi, Hwasan, Asan, tsan, Fuzzer, scs:
+ sanitizer := &sanitizerSplitMutator{t}
+ ctx.TopDown(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator)
+ ctx.Transition(t.variationName(), sanitizer)
case Memtag_heap, intOverflow:
// do nothing
default:
@@ -276,7 +277,6 @@
type SanitizeProperties struct {
Sanitize SanitizeUserProps `android:"arch_variant"`
SanitizerEnabled bool `blueprint:"mutated"`
- SanitizeDepTypes []SanitizerType `blueprint:"mutated"`
MinimalRuntimeDep bool `blueprint:"mutated"`
BuiltinsDep bool `blueprint:"mutated"`
UbsanRuntimeDep bool `blueprint:"mutated"`
@@ -430,7 +430,7 @@
}
// Enable Memtag for all components in the include paths (for Aarch64 only)
- if ctx.Arch().ArchType == android.Arm64 {
+ if ctx.Arch().ArchType == android.Arm64 && ctx.toolchain().Bionic() {
if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
if s.Memtag_heap == nil {
s.Memtag_heap = proptools.BoolPtr(true)
@@ -460,17 +460,17 @@
}
// HWASan requires AArch64 hardware feature (top-byte-ignore).
- if ctx.Arch().ArchType != android.Arm64 {
+ if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
s.Hwaddress = nil
}
// SCS is only implemented on AArch64.
- if ctx.Arch().ArchType != android.Arm64 {
+ if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
s.Scs = nil
}
// Memtag_heap is only implemented on AArch64.
- if ctx.Arch().ArchType != android.Arm64 {
+ if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
s.Memtag_heap = nil
}
@@ -588,13 +588,6 @@
}
func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
- minimalRuntimeLib := config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(ctx.toolchain()) + ".a"
-
- if sanitize.Properties.MinimalRuntimeDep {
- flags.Local.LdFlags = append(flags.Local.LdFlags,
- "-Wl,--exclude-libs,"+minimalRuntimeLib)
- }
-
if !sanitize.Properties.SanitizerEnabled && !sanitize.Properties.UbsanRuntimeDep {
return flags
}
@@ -717,14 +710,14 @@
// Host sanitizers only link symbols in the final executable, so
// there will always be undefined symbols in intermediate libraries.
_, flags.Global.LdFlags = removeFromList("-Wl,--no-undefined", flags.Global.LdFlags)
-
- // non-Bionic toolchain prebuilts are missing UBSan's vptr and function san
- flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function")
}
- if enableMinimalRuntime(sanitize) {
- flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
+ if !ctx.toolchain().Bionic() {
+ // non-Bionic toolchain prebuilts are missing UBSan's vptr and function san.
+ // Musl toolchain prebuilts have vptr and function sanitizers, but enabling them
+ // implicitly enables RTTI which causes RTTI mismatch issues with dependencies.
+
+ flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function")
}
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
@@ -735,6 +728,11 @@
} else {
flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
}
+
+ if enableMinimalRuntime(sanitize) {
+ flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
+ }
+
// http://b/119329758, Android core does not boot up with this sanitizer yet.
if toDisableImplicitIntegerChange(flags.Local.CFlags) {
flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=implicit-integer-sign-change")
@@ -906,7 +904,7 @@
// Determines if the current module is a static library going to be captured
// as vendor snapshot. Such modules must create both cfi and non-cfi variants,
// except for ones which explicitly disable cfi.
-func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool {
+func needsCfiForVendorSnapshot(mctx android.BaseModuleContext) bool {
if snapshot.IsVendorProprietaryModule(mctx) {
return false
}
@@ -934,62 +932,232 @@
!c.IsSanitizerExplicitlyDisabled(cfi)
}
-// Propagate sanitizer requirements down from binaries
-func sanitizerDepsMutator(t SanitizerType) func(android.TopDownMutatorContext) {
- return func(mctx android.TopDownMutatorContext) {
- if c, ok := mctx.Module().(PlatformSanitizeable); ok {
- enabled := c.IsSanitizerEnabled(t)
- if t == cfi && needsCfiForVendorSnapshot(mctx) {
- // We shouldn't change the result of isSanitizerEnabled(cfi) to correctly
- // determine defaultVariation in sanitizerMutator below.
- // Instead, just mark SanitizeDep to forcefully create cfi variant.
+type sanitizerSplitMutator struct {
+ sanitizer SanitizerType
+}
+
+// If an APEX is sanitized or not depends on whether it contains at least one
+// sanitized module. Transition mutators cannot propagate information up the
+// dependency graph this way, so we need an auxiliary mutator to do so.
+func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.TopDownMutatorContext) {
+ if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
+ enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ if c, ok := dep.(*Module); ok && c.sanitize.isSanitizerEnabled(s.sanitizer) {
enabled = true
- c.SetSanitizeDep(t)
}
- if enabled {
- isSanitizableDependencyTag := c.SanitizableDepTagChecker()
- mctx.WalkDeps(func(child, parent android.Module) bool {
- if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
- return false
- }
- if d, ok := child.(PlatformSanitizeable); ok && d.SanitizePropDefined() &&
- !d.SanitizeNever() &&
- !d.IsSanitizerExplicitlyDisabled(t) {
- if t == cfi || t == Hwasan || t == scs || t == Asan {
- if d.StaticallyLinked() && d.SanitizerSupported(t) {
- // Rust does not support some of these sanitizers, so we need to check if it's
- // supported before setting this true.
- d.SetSanitizeDep(t)
- }
- } else {
- d.SetSanitizeDep(t)
- }
- }
- return true
- })
+ })
+
+ if enabled {
+ sanitizeable.EnableSanitizer(s.sanitizer.name())
+ }
+ }
+}
+
+func (s *sanitizerSplitMutator) Split(ctx android.BaseModuleContext) []string {
+ if c, ok := ctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
+ if s.sanitizer == cfi && needsCfiForVendorSnapshot(ctx) {
+ return []string{"", s.sanitizer.variationName()}
+ }
+
+ // If the given sanitizer is not requested in the .bp file for a module, it
+ // won't automatically build the sanitized variation.
+ if !c.IsSanitizerEnabled(s.sanitizer) {
+ return []string{""}
+ }
+
+ if c.Binary() {
+ // If a sanitizer is enabled for a binary, we do not build the version
+ // without the sanitizer
+ return []string{s.sanitizer.variationName()}
+ } else if c.StaticallyLinked() || c.Header() {
+ // For static libraries, we build both versions. Some Make modules
+ // apparently depend on this behavior.
+ return []string{"", s.sanitizer.variationName()}
+ } else {
+ // We only build the requested variation of dynamic libraries
+ return []string{s.sanitizer.variationName()}
+ }
+ }
+
+ if _, ok := ctx.Module().(JniSanitizeable); ok {
+ // TODO: this should call into JniSanitizable.IsSanitizerEnabledForJni but
+ // that is short-circuited for now
+ return []string{""}
+ }
+
+ // If an APEX has a sanitized dependency, we build the APEX in the sanitized
+ // variation. This is useful because such APEXes require extra dependencies.
+ if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
+ enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
+ if enabled {
+ return []string{s.sanitizer.variationName()}
+ } else {
+ return []string{""}
+ }
+ }
+
+ if c, ok := ctx.Module().(*Module); ok {
+ //TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
+
+ // Check if it's a snapshot module supporting sanitizer
+ if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerEnabled(s.sanitizer) {
+ return []string{"", s.sanitizer.variationName()}
+ } else {
+ return []string{""}
+ }
+ }
+
+ return []string{""}
+}
+
+func (s *sanitizerSplitMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+ if c, ok := ctx.Module().(PlatformSanitizeable); ok {
+ if !c.SanitizableDepTagChecker()(ctx.DepTag()) {
+ // If the dependency is through a non-sanitizable tag, use the
+ // non-sanitized variation
+ return ""
+ }
+
+ return sourceVariation
+ } else if _, ok := ctx.Module().(JniSanitizeable); ok {
+ // TODO: this should call into JniSanitizable.IsSanitizerEnabledForJni but
+ // that is short-circuited for now
+ return ""
+ } else {
+ // Otherwise, do not rock the boat.
+ return sourceVariation
+ }
+}
+
+func (s *sanitizerSplitMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+ if d, ok := ctx.Module().(PlatformSanitizeable); ok {
+ if dm, ok := ctx.Module().(*Module); ok {
+ if ss, ok := dm.linker.(snapshotSanitizer); ok && ss.isSanitizerEnabled(s.sanitizer) {
+ return incomingVariation
}
- } else if jniSanitizeable, ok := mctx.Module().(JniSanitizeable); ok {
- // If it's a Java module with native dependencies through jni,
- // set the sanitizer for them
- if jniSanitizeable.IsSanitizerEnabledForJni(mctx, t.name()) {
- mctx.VisitDirectDeps(func(child android.Module) {
- if c, ok := child.(PlatformSanitizeable); ok &&
- mctx.OtherModuleDependencyTag(child) == JniFuzzLibTag &&
- c.SanitizePropDefined() &&
- !c.SanitizeNever() &&
- !c.IsSanitizerExplicitlyDisabled(t) {
- c.SetSanitizeDep(t)
- }
- })
+ }
+
+ if !d.SanitizePropDefined() ||
+ d.SanitizeNever() ||
+ d.IsSanitizerExplicitlyDisabled(s.sanitizer) ||
+ !d.SanitizerSupported(s.sanitizer) {
+ // If a module opts out of a sanitizer, use its non-sanitized variation
+ return ""
+ }
+
+ // Binaries are always built in the variation they requested.
+ if d.Binary() {
+ if d.IsSanitizerEnabled(s.sanitizer) {
+ return s.sanitizer.variationName()
+ } else {
+ return ""
}
- } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
- // If an APEX module includes a lib which is enabled for a sanitizer T, then
- // the APEX module is also enabled for the same sanitizer type.
- mctx.VisitDirectDeps(func(child android.Module) {
- if c, ok := child.(*Module); ok && c.sanitize.isSanitizerEnabled(t) {
- sanitizeable.EnableSanitizer(t.name())
+ }
+
+ // If a shared library requests to be sanitized, it will be built for that
+ // sanitizer. Otherwise, some sanitizers propagate through shared library
+ // dependency edges, some do not.
+ if !d.StaticallyLinked() && !d.Header() {
+ if d.IsSanitizerEnabled(s.sanitizer) {
+ return s.sanitizer.variationName()
+ }
+
+ if s.sanitizer == cfi || s.sanitizer == Hwasan || s.sanitizer == scs || s.sanitizer == Asan {
+ return ""
+ }
+ }
+
+ // Static and header libraries inherit whether they are sanitized from the
+ // module they are linked into
+ return incomingVariation
+ } else if d, ok := ctx.Module().(Sanitizeable); ok {
+ // If an APEX contains a sanitized module, it will be built in the variation
+ // corresponding to that sanitizer.
+ enabled := d.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
+ if enabled {
+ return s.sanitizer.variationName()
+ }
+
+ return incomingVariation
+ }
+
+ return ""
+}
+
+func (s *sanitizerSplitMutator) Mutate(mctx android.BottomUpMutatorContext, variationName string) {
+ sanitizerVariation := variationName == s.sanitizer.variationName()
+
+ if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
+ sanitizerEnabled := c.IsSanitizerEnabled(s.sanitizer)
+
+ oneMakeVariation := false
+ if c.StaticallyLinked() || c.Header() {
+ if s.sanitizer != cfi && s.sanitizer != scs && s.sanitizer != Hwasan {
+ // These sanitizers export only one variation to Make. For the rest,
+ // Make targets can depend on both the sanitized and non-sanitized
+ // versions.
+ oneMakeVariation = true
+ }
+ } else if !c.Binary() {
+ // Shared library. These are the sanitizers that do propagate through shared
+ // library dependencies and therefore can cause multiple variations of a
+ // shared library to be built.
+ if s.sanitizer != cfi && s.sanitizer != Hwasan && s.sanitizer != scs && s.sanitizer != Asan {
+ oneMakeVariation = true
+ }
+ }
+
+ if oneMakeVariation {
+ if sanitizerEnabled != sanitizerVariation {
+ c.SetPreventInstall()
+ c.SetHideFromMake()
+ }
+ }
+
+ if sanitizerVariation {
+ c.SetSanitizer(s.sanitizer, true)
+
+ // CFI is incompatible with ASAN so disable it in ASAN variations
+ if s.sanitizer.incompatibleWithCfi() {
+ cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
+ if mctx.Device() && cfiSupported {
+ c.SetSanitizer(cfi, false)
}
- })
+ }
+
+ // locate the asan libraries under /data/asan
+ if !c.Binary() && !c.StaticallyLinked() && !c.Header() && mctx.Device() && s.sanitizer == Asan && sanitizerEnabled {
+ c.SetInSanitizerDir()
+ }
+
+ if c.StaticallyLinked() && c.ExportedToMake() {
+ if s.sanitizer == Hwasan {
+ hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
+ } else if s.sanitizer == cfi {
+ cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
+ }
+ }
+ } else if c.IsSanitizerEnabled(s.sanitizer) {
+ // Disable the sanitizer for the non-sanitized variation
+ c.SetSanitizer(s.sanitizer, false)
+ }
+ } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
+ // If an APEX has sanitized dependencies, it gets a few more dependencies
+ if sanitizerVariation {
+ sanitizeable.AddSanitizerDependencies(mctx, s.sanitizer.name())
+ }
+ } else if c, ok := mctx.Module().(*Module); ok {
+ if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerEnabled(s.sanitizer) {
+ c.linker.(snapshotSanitizer).setSanitizerVariation(s.sanitizer, sanitizerVariation)
+
+ // Export the static lib name to make
+ if c.static() && c.ExportedToMake() {
+ if s.sanitizer == cfi {
+ // use BaseModuleName which is the name for Make.
+ cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
+ }
+ }
}
}
}
@@ -1217,7 +1385,7 @@
}
// static executable gets static runtime libs
- depTag := libraryDependencyTag{Kind: staticLibraryDependency}
+ depTag := libraryDependencyTag{Kind: staticLibraryDependency, unexportedSymbols: true}
variations := append(mctx.Target().Variations(),
blueprint.Variation{Mutator: "link", Variation: "static"})
if c.Device() {
@@ -1289,7 +1457,7 @@
type Sanitizeable interface {
android.Module
- IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool
+ IsSanitizerEnabled(config android.Config, sanitizerName string) bool
EnableSanitizer(sanitizerName string)
AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string)
}
@@ -1315,16 +1483,6 @@
return c.sanitize.isSanitizerEnabled(t)
}
-func (c *Module) SanitizeDep(t SanitizerType) bool {
- for _, e := range c.sanitize.Properties.SanitizeDepTypes {
- if t == e {
- return true
- }
- }
-
- return false
-}
-
func (c *Module) StaticallyLinked() bool {
return c.static()
}
@@ -1341,123 +1499,8 @@
}
}
-func (c *Module) SetSanitizeDep(t SanitizerType) {
- if !c.SanitizeDep(t) {
- c.sanitize.Properties.SanitizeDepTypes = append(c.sanitize.Properties.SanitizeDepTypes, t)
- }
-}
-
var _ PlatformSanitizeable = (*Module)(nil)
-// Create sanitized variants for modules that need them
-func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) {
- return func(mctx android.BottomUpMutatorContext) {
- if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
-
- // Make sure we're not setting CFI to any value if it's not supported.
- cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
-
- if c.Binary() && c.IsSanitizerEnabled(t) {
- modules := mctx.CreateVariations(t.variationName())
- modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
- } else if c.IsSanitizerEnabled(t) || c.SanitizeDep(t) {
- isSanitizerEnabled := c.IsSanitizerEnabled(t)
- if c.StaticallyLinked() || c.Header() || t == Fuzzer {
- // Static and header libs are split into non-sanitized and sanitized variants.
- // Shared libs are not split. However, for asan and fuzzer, we split even for shared
- // libs because a library sanitized for asan/fuzzer can't be linked from a library
- // that isn't sanitized for asan/fuzzer.
- //
- // Note for defaultVariation: since we don't split for shared libs but for static/header
- // libs, it is possible for the sanitized variant of a static/header lib to depend
- // on non-sanitized variant of a shared lib. Such unfulfilled variation causes an
- // error when the module is split. defaultVariation is the name of the variation that
- // will be used when such a dangling dependency occurs during the split of the current
- // module. By setting it to the name of the sanitized variation, the dangling dependency
- // is redirected to the sanitized variant of the dependent module.
- defaultVariation := t.variationName()
- // Not all PlatformSanitizeable modules support the CFI sanitizer
- mctx.SetDefaultDependencyVariation(&defaultVariation)
-
- modules := mctx.CreateVariations("", t.variationName())
- modules[0].(PlatformSanitizeable).SetSanitizer(t, false)
- modules[1].(PlatformSanitizeable).SetSanitizer(t, true)
-
- if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
- // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
- // are incompatible with cfi
- modules[1].(PlatformSanitizeable).SetSanitizer(cfi, false)
- }
-
- // For cfi/scs/hwasan, we can export both sanitized and un-sanitized variants
- // to Make, because the sanitized version has a different suffix in name.
- // For other types of sanitizers, suppress the variation that is disabled.
- if t != cfi && t != scs && t != Hwasan {
- if isSanitizerEnabled {
- modules[0].(PlatformSanitizeable).SetPreventInstall()
- modules[0].(PlatformSanitizeable).SetHideFromMake()
- } else {
- modules[1].(PlatformSanitizeable).SetPreventInstall()
- modules[1].(PlatformSanitizeable).SetHideFromMake()
- }
- }
-
- // Export the static lib name to make
- if c.StaticallyLinked() && c.ExportedToMake() {
- if t == cfi {
- cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
- } else if t == Hwasan {
- hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
- }
- }
- } else {
- // Shared libs are not split. Only the sanitized variant is created.
- modules := mctx.CreateVariations(t.variationName())
- modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
-
- // locate the asan libraries under /data/asan
- if mctx.Device() && t == Asan && isSanitizerEnabled {
- modules[0].(PlatformSanitizeable).SetInSanitizerDir()
- }
-
- if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
- // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
- // are incompatible with cfi
- modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false)
- }
- }
- }
- } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) {
- // APEX fuzz modules fall here
- sanitizeable.AddSanitizerDependencies(mctx, t.name())
- mctx.CreateVariations(t.variationName())
- } else if _, ok := mctx.Module().(JniSanitizeable); ok {
- // Java fuzz modules fall here
- mctx.CreateVariations(t.variationName())
- } else if c, ok := mctx.Module().(*Module); ok {
- //TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
-
- // Check if it's a snapshot module supporting sanitizer
- if s, ok := c.linker.(snapshotSanitizer); ok && s.isSanitizerEnabled(t) {
- // Set default variation as above.
- defaultVariation := t.variationName()
- mctx.SetDefaultDependencyVariation(&defaultVariation)
- modules := mctx.CreateVariations("", t.variationName())
- modules[0].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, false)
- modules[1].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, true)
-
- // Export the static lib name to make
- if c.static() && c.ExportedToMake() {
- if t == cfi {
- // use BaseModuleName which is the name for Make.
- cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
- }
- }
- }
- }
- }
-}
-
type sanitizerStaticLibsMap struct {
// libsMap contains one list of modules per each image and each arch.
// e.g. libs[vendor]["arm"] contains arm modules installed to vendor
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index c1ca034..5d7e7d8 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "runtime"
"strings"
"testing"
@@ -201,6 +202,125 @@
t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
}
+func TestUbsan(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("requires linux")
+ }
+
+ bp := `
+ cc_binary {
+ name: "bin_with_ubsan",
+ host_supported: true,
+ shared_libs: [
+ "libshared",
+ ],
+ static_libs: [
+ "libstatic",
+ "libnoubsan",
+ ],
+ sanitize: {
+ undefined: true,
+ }
+ }
+
+ cc_binary {
+ name: "bin_depends_ubsan",
+ host_supported: true,
+ shared_libs: [
+ "libshared",
+ ],
+ static_libs: [
+ "libstatic",
+ "libubsan",
+ "libnoubsan",
+ ],
+ }
+
+ cc_binary {
+ name: "bin_no_ubsan",
+ host_supported: true,
+ shared_libs: [
+ "libshared",
+ ],
+ static_libs: [
+ "libstatic",
+ "libnoubsan",
+ ],
+ }
+
+ cc_library_shared {
+ name: "libshared",
+ host_supported: true,
+ shared_libs: ["libtransitive"],
+ }
+
+ cc_library_shared {
+ name: "libtransitive",
+ host_supported: true,
+ }
+
+ cc_library_static {
+ name: "libubsan",
+ host_supported: true,
+ sanitize: {
+ undefined: true,
+ }
+ }
+
+ cc_library_static {
+ name: "libstatic",
+ host_supported: true,
+ }
+
+ cc_library_static {
+ name: "libnoubsan",
+ host_supported: true,
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ ).RunTestWithBp(t, bp)
+
+ check := func(t *testing.T, result *android.TestResult, variant string) {
+ staticVariant := variant + "_static"
+
+ minimalRuntime := result.ModuleForTests("libclang_rt.ubsan_minimal", staticVariant)
+
+ // The binaries, one with ubsan and one without
+ binWithUbsan := result.ModuleForTests("bin_with_ubsan", variant)
+ binDependsUbsan := result.ModuleForTests("bin_depends_ubsan", variant)
+ binNoUbsan := result.ModuleForTests("bin_no_ubsan", variant)
+
+ android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_with_ubsan static libs",
+ strings.Split(binWithUbsan.Rule("ld").Args["libFlags"], " "),
+ minimalRuntime.OutputFiles(t, "")[0].String())
+
+ android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_depends_ubsan static libs",
+ strings.Split(binDependsUbsan.Rule("ld").Args["libFlags"], " "),
+ minimalRuntime.OutputFiles(t, "")[0].String())
+
+ android.AssertStringListDoesNotContain(t, "unexpected libclang_rt.ubsan_minimal in bin_no_ubsan static libs",
+ strings.Split(binNoUbsan.Rule("ld").Args["libFlags"], " "),
+ minimalRuntime.OutputFiles(t, "")[0].String())
+
+ android.AssertStringListContains(t, "missing -Wl,--exclude-libs for minimal runtime in bin_with_ubsan",
+ strings.Split(binWithUbsan.Rule("ld").Args["ldFlags"], " "),
+ "-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base())
+
+ android.AssertStringListContains(t, "missing -Wl,--exclude-libs for minimal runtime in bin_depends_ubsan static libs",
+ strings.Split(binDependsUbsan.Rule("ld").Args["ldFlags"], " "),
+ "-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base())
+
+ android.AssertStringListDoesNotContain(t, "unexpected -Wl,--exclude-libs for minimal runtime in bin_no_ubsan static libs",
+ strings.Split(binNoUbsan.Rule("ld").Args["ldFlags"], " "),
+ "-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base())
+ }
+
+ t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) })
+ t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
+}
+
type MemtagNoteType int
const (
diff --git a/cc/stl.go b/cc/stl.go
index 0f2a878..85a06da 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -25,6 +25,16 @@
return family
}
+func deduplicateStlInput(stl string) string {
+ switch stl {
+ case "c++_shared":
+ return "libc++"
+ case "c++_static":
+ return "libc++_static"
+ }
+ return stl
+}
+
func getNdkStlFamilyAndLinkType(m LinkableInterface) (string, string) {
stl := m.SelectedStl()
switch stl {
@@ -66,18 +76,18 @@
} else if ctx.header() {
s = "none"
}
+ if s == "none" {
+ return ""
+ }
+ s = deduplicateStlInput(s)
if ctx.useSdk() && ctx.Device() {
switch s {
case "", "system":
return "ndk_system"
- case "c++_shared", "c++_static":
- return "ndk_lib" + s
case "libc++":
return "ndk_libc++_shared"
case "libc++_static":
return "ndk_libc++_static"
- case "none":
- return ""
default:
ctx.ModuleErrorf("stl: %q is not a supported STL with sdk_version set", s)
return ""
@@ -87,8 +97,6 @@
case "libc++", "libc++_static", "":
// Only use static libc++ for Windows.
return "libc++_static"
- case "none":
- return ""
default:
ctx.ModuleErrorf("stl: %q is not a supported STL for windows", s)
return ""
@@ -97,12 +105,6 @@
switch s {
case "libc++", "libc++_static":
return s
- case "c++_shared":
- return "libc++"
- case "c++_static":
- return "libc++_static"
- case "none":
- return ""
case "", "system":
if ctx.static() {
return "libc++_static"
diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py
index f8d1841..471a12f 100644
--- a/cc/symbolfile/__init__.py
+++ b/cc/symbolfile/__init__.py
@@ -78,12 +78,17 @@
@property
def has_mode_tags(self) -> bool:
"""Returns True if any mode tags (apex, llndk, etc) are set."""
- return self.has_apex_tags or self.has_llndk_tags
+ return self.has_apex_tags or self.has_llndk_tags or self.has_systemapi_tags
@property
def has_apex_tags(self) -> bool:
"""Returns True if any APEX tags are set."""
- return 'apex' in self.tags or 'systemapi' in self.tags
+ return 'apex' in self.tags
+
+ @property
+ def has_systemapi_tags(self) -> bool:
+ """Returns True if any APEX tags are set."""
+ return 'systemapi' in self.tags
@property
def has_llndk_tags(self) -> bool:
@@ -198,50 +203,57 @@
"""
return split_tag(tag)[1]
-
-def _should_omit_tags(tags: Tags, arch: Arch, api: int, llndk: bool,
- apex: bool) -> bool:
- """Returns True if the tagged object should be omitted.
-
- This defines the rules shared between version tagging and symbol tagging.
+class Filter:
+ """A filter encapsulates a condition that tells whether a version or a
+ symbol should be omitted or not
"""
- # The apex and llndk tags will only exclude APIs from other modes. If in
- # APEX or LLNDK mode and neither tag is provided, we fall back to the
- # default behavior because all NDK symbols are implicitly available to APEX
- # and LLNDK.
- if tags.has_mode_tags:
- if not apex and not llndk:
+
+ def __init__(self, arch: Arch, api: int, llndk: bool = False, apex: bool = False, systemapi: bool = False):
+ self.arch = arch
+ self.api = api
+ self.llndk = llndk
+ self.apex = apex
+ self.systemapi = systemapi
+
+ def _should_omit_tags(self, tags: Tags) -> bool:
+ """Returns True if the tagged object should be omitted.
+
+ This defines the rules shared between version tagging and symbol tagging.
+ """
+ # The apex and llndk tags will only exclude APIs from other modes. If in
+ # APEX or LLNDK mode and neither tag is provided, we fall back to the
+ # default behavior because all NDK symbols are implicitly available to
+ # APEX and LLNDK.
+ if tags.has_mode_tags:
+ if self.apex and tags.has_apex_tags:
+ return False
+ if self.llndk and tags.has_llndk_tags:
+ return False
+ if self.systemapi and tags.has_systemapi_tags:
+ return False
return True
- if apex and not tags.has_apex_tags:
+ if not symbol_in_arch(tags, self.arch):
return True
- if llndk and not tags.has_llndk_tags:
+ if not symbol_in_api(tags, self.arch, self.api):
return True
- if not symbol_in_arch(tags, arch):
- return True
- if not symbol_in_api(tags, arch, api):
- return True
- return False
+ return False
+ def should_omit_version(self, version: Version) -> bool:
+ """Returns True if the version section should be omitted.
-def should_omit_version(version: Version, arch: Arch, api: int, llndk: bool,
- apex: bool) -> bool:
- """Returns True if the version section should be omitted.
+ We want to omit any sections that do not have any symbols we'll have in
+ the stub library. Sections that contain entirely future symbols or only
+ symbols for certain architectures.
+ """
+ if version.is_private:
+ return True
+ if version.tags.has_platform_only_tags:
+ return True
+ return self._should_omit_tags(version.tags)
- We want to omit any sections that do not have any symbols we'll have in the
- stub library. Sections that contain entirely future symbols or only symbols
- for certain architectures.
- """
- if version.is_private:
- return True
- if version.tags.has_platform_only_tags:
- return True
- return _should_omit_tags(version.tags, arch, api, llndk, apex)
-
-
-def should_omit_symbol(symbol: Symbol, arch: Arch, api: int, llndk: bool,
- apex: bool) -> bool:
- """Returns True if the symbol should be omitted."""
- return _should_omit_tags(symbol.tags, arch, api, llndk, apex)
+ def should_omit_symbol(self, symbol: Symbol) -> bool:
+ """Returns True if the symbol should be omitted."""
+ return self._should_omit_tags(symbol.tags)
def symbol_in_arch(tags: Tags, arch: Arch) -> bool:
@@ -316,14 +328,10 @@
class SymbolFileParser:
"""Parses NDK symbol files."""
- def __init__(self, input_file: TextIO, api_map: ApiMap, arch: Arch,
- api: int, llndk: bool, apex: bool) -> None:
+ def __init__(self, input_file: TextIO, api_map: ApiMap, filt: Filter) -> None:
self.input_file = input_file
self.api_map = api_map
- self.arch = arch
- self.api = api
- self.llndk = llndk
- self.apex = apex
+ self.filter = filt
self.current_line: Optional[str] = None
def parse(self) -> List[Version]:
@@ -352,13 +360,11 @@
symbol_names = set()
multiply_defined_symbols = set()
for version in versions:
- if should_omit_version(version, self.arch, self.api, self.llndk,
- self.apex):
+ if self.filter.should_omit_version(version):
continue
for symbol in version.symbols:
- if should_omit_symbol(symbol, self.arch, self.api, self.llndk,
- self.apex):
+ if self.filter.should_omit_symbol(symbol):
continue
if symbol.name in symbol_names:
diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py
index c1e8219..e17a8d0 100644
--- a/cc/symbolfile/test_symbolfile.py
+++ b/cc/symbolfile/test_symbolfile.py
@@ -19,7 +19,8 @@
import unittest
import symbolfile
-from symbolfile import Arch, Tag, Tags, Version
+from symbolfile import Arch, Tag, Tags, Version, Symbol, Filter
+from copy import copy
# pylint: disable=missing-docstring
@@ -202,178 +203,188 @@
class OmitVersionTest(unittest.TestCase):
+ def setUp(self) -> None:
+ self.filter = Filter(arch = Arch('arm'), api = 9)
+ self.version = Version('foo', None, Tags(), [])
+
+ def assertOmit(self, f: Filter, v: Version) -> None:
+ self.assertTrue(f.should_omit_version(v))
+
+ def assertInclude(self, f: Filter, v: Version) -> None:
+ self.assertFalse(f.should_omit_version(v))
+
def test_omit_private(self) -> None:
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
- False, False))
+ f = self.filter
+ v = self.version
- self.assertTrue(
- symbolfile.should_omit_version(
- symbolfile.Version('foo_PRIVATE', None, Tags(), []),
- Arch('arm'), 9, False, False))
- self.assertTrue(
- symbolfile.should_omit_version(
- symbolfile.Version('foo_PLATFORM', None, Tags(), []),
- Arch('arm'), 9, False, False))
+ self.assertInclude(f, v)
- self.assertTrue(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None,
- Tags.from_strs(['platform-only']), []),
- Arch('arm'), 9, False, False))
+ v.name = 'foo_PRIVATE'
+ self.assertOmit(f, v)
+
+ v.name = 'foo_PLATFORM'
+ self.assertOmit(f, v)
+
+ v.name = 'foo'
+ v.tags = Tags.from_strs(['platform-only'])
+ self.assertOmit(f, v)
def test_omit_llndk(self) -> None:
- self.assertTrue(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags.from_strs(['llndk']), []),
- Arch('arm'), 9, False, False))
+ f = self.filter
+ v = self.version
+ v_llndk = copy(v)
+ v_llndk.tags = Tags.from_strs(['llndk'])
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
- True, False))
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags.from_strs(['llndk']), []),
- Arch('arm'), 9, True, False))
+ self.assertOmit(f, v_llndk)
+
+ f.llndk = True
+ self.assertInclude(f, v)
+ self.assertInclude(f, v_llndk)
def test_omit_apex(self) -> None:
- self.assertTrue(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags.from_strs(['apex']), []),
- Arch('arm'), 9, False, False))
+ f = self.filter
+ v = self.version
+ v_apex = copy(v)
+ v_apex.tags = Tags.from_strs(['apex'])
+ v_systemapi = copy(v)
+ v_systemapi.tags = Tags.from_strs(['systemapi'])
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
- False, True))
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags.from_strs(['apex']), []),
- Arch('arm'), 9, False, True))
+ self.assertOmit(f, v_apex)
+
+ f.apex = True
+ self.assertInclude(f, v)
+ self.assertInclude(f, v_apex)
+ self.assertOmit(f, v_systemapi)
def test_omit_systemapi(self) -> None:
- self.assertTrue(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags.from_strs(['systemapi']),
- []), Arch('arm'), 9, False, False))
+ f = self.filter
+ v = self.version
+ v_apex = copy(v)
+ v_apex.tags = Tags.from_strs(['apex'])
+ v_systemapi = copy(v)
+ v_systemapi.tags = Tags.from_strs(['systemapi'])
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
- False, True))
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags.from_strs(['systemapi']),
- []), Arch('arm'), 9, False, True))
+ self.assertOmit(f, v_systemapi)
+
+ f.systemapi = True
+ self.assertInclude(f, v)
+ self.assertInclude(f, v_systemapi)
+ self.assertOmit(f, v_apex)
def test_omit_arch(self) -> None:
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
- False, False))
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags.from_strs(['arm']), []),
- Arch('arm'), 9, False, False))
+ f_arm = self.filter
+ v_none = self.version
+ self.assertInclude(f_arm, v_none)
- self.assertTrue(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags.from_strs(['x86']), []),
- Arch('arm'), 9, False, False))
+ v_arm = copy(v_none)
+ v_arm.tags = Tags.from_strs(['arm'])
+ self.assertInclude(f_arm, v_arm)
+
+ v_x86 = copy(v_none)
+ v_x86.tags = Tags.from_strs(['x86'])
+ self.assertOmit(f_arm, v_x86)
def test_omit_api(self) -> None:
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
- False, False))
- self.assertFalse(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None,
- Tags.from_strs(['introduced=9']), []),
- Arch('arm'), 9, False, False))
+ f_api9 = self.filter
+ v_none = self.version
+ self.assertInclude(f_api9, v_none)
- self.assertTrue(
- symbolfile.should_omit_version(
- symbolfile.Version('foo', None,
- Tags.from_strs(['introduced=14']), []),
- Arch('arm'), 9, False, False))
+ v_api9 = copy(v_none)
+ v_api9.tags = Tags.from_strs(['introduced=9'])
+ self.assertInclude(f_api9, v_api9)
+
+ v_api14 = copy(v_none)
+ v_api14.tags = Tags.from_strs(['introduced=14'])
+ self.assertOmit(f_api9, v_api14)
class OmitSymbolTest(unittest.TestCase):
- def test_omit_llndk(self) -> None:
- self.assertTrue(
- symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', Tags.from_strs(['llndk'])),
- Arch('arm'), 9, False, False))
+ def setUp(self) -> None:
+ self.filter = Filter(arch = Arch('arm'), api = 9)
- self.assertFalse(
- symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
- Arch('arm'), 9, True, False))
- self.assertFalse(
- symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', Tags.from_strs(['llndk'])),
- Arch('arm'), 9, True, False))
+ def assertOmit(self, f: Filter, s: Symbol) -> None:
+ self.assertTrue(f.should_omit_symbol(s))
+
+ def assertInclude(self, f: Filter, s: Symbol) -> None:
+ self.assertFalse(f.should_omit_symbol(s))
+
+ def test_omit_llndk(self) -> None:
+ f_none = self.filter
+ f_llndk = copy(f_none)
+ f_llndk.llndk = True
+
+ s_none = Symbol('foo', Tags())
+ s_llndk = Symbol('foo', Tags.from_strs(['llndk']))
+
+ self.assertOmit(f_none, s_llndk)
+ self.assertInclude(f_llndk, s_none)
+ self.assertInclude(f_llndk, s_llndk)
def test_omit_apex(self) -> None:
- self.assertTrue(
- symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', Tags.from_strs(['apex'])),
- Arch('arm'), 9, False, False))
+ f_none = self.filter
+ f_apex = copy(f_none)
+ f_apex.apex = True
- self.assertFalse(
- symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
- Arch('arm'), 9, False, True))
- self.assertFalse(
- symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', Tags.from_strs(['apex'])),
- Arch('arm'), 9, False, True))
+ s_none = Symbol('foo', Tags())
+ s_apex = Symbol('foo', Tags.from_strs(['apex']))
+ s_systemapi = Symbol('foo', Tags.from_strs(['systemapi']))
+
+ self.assertOmit(f_none, s_apex)
+ self.assertInclude(f_apex, s_none)
+ self.assertInclude(f_apex, s_apex)
+ self.assertOmit(f_apex, s_systemapi)
def test_omit_systemapi(self) -> None:
- self.assertTrue(
- symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', Tags.from_strs(['systemapi'])),
- Arch('arm'), 9, False, False))
+ f_none = self.filter
+ f_systemapi = copy(f_none)
+ f_systemapi.systemapi = True
- self.assertFalse(
- symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
- Arch('arm'), 9, False, True))
- self.assertFalse(
- symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', Tags.from_strs(['systemapi'])),
- Arch('arm'), 9, False, True))
+ s_none = Symbol('foo', Tags())
+ s_apex = Symbol('foo', Tags.from_strs(['apex']))
+ s_systemapi = Symbol('foo', Tags.from_strs(['systemapi']))
+
+ self.assertOmit(f_none, s_systemapi)
+ self.assertInclude(f_systemapi, s_none)
+ self.assertInclude(f_systemapi, s_systemapi)
+ self.assertOmit(f_systemapi, s_apex)
+
+ def test_omit_apex_and_systemapi(self) -> None:
+ f = self.filter
+ f.systemapi = True
+ f.apex = True
+
+ s_none = Symbol('foo', Tags())
+ s_apex = Symbol('foo', Tags.from_strs(['apex']))
+ s_systemapi = Symbol('foo', Tags.from_strs(['systemapi']))
+ self.assertInclude(f, s_none)
+ self.assertInclude(f, s_apex)
+ self.assertInclude(f, s_systemapi)
def test_omit_arch(self) -> None:
- self.assertFalse(
- symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
- Arch('arm'), 9, False, False))
- self.assertFalse(
- symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', Tags.from_strs(['arm'])), Arch('arm'),
- 9, False, False))
+ f_arm = self.filter
+ s_none = Symbol('foo', Tags())
+ s_arm = Symbol('foo', Tags.from_strs(['arm']))
+ s_x86 = Symbol('foo', Tags.from_strs(['x86']))
- self.assertTrue(
- symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', Tags.from_strs(['x86'])), Arch('arm'),
- 9, False, False))
+ self.assertInclude(f_arm, s_none)
+ self.assertInclude(f_arm, s_arm)
+ self.assertOmit(f_arm, s_x86)
def test_omit_api(self) -> None:
- self.assertFalse(
- symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
- Arch('arm'), 9, False, False))
- self.assertFalse(
- symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', Tags.from_strs(['introduced=9'])),
- Arch('arm'), 9, False, False))
+ f_api9 = self.filter
+ s_none = Symbol('foo', Tags())
+ s_api9 = Symbol('foo', Tags.from_strs(['introduced=9']))
+ s_api14 = Symbol('foo', Tags.from_strs(['introduced=14']))
- self.assertTrue(
- symbolfile.should_omit_symbol(
- symbolfile.Symbol('foo', Tags.from_strs(['introduced=14'])),
- Arch('arm'), 9, False, False))
+ self.assertInclude(f_api9, s_none)
+ self.assertInclude(f_api9, s_api9)
+ self.assertOmit(f_api9, s_api14)
class SymbolFileParseTest(unittest.TestCase):
+ def setUp(self) -> None:
+ self.filter = Filter(arch = Arch('arm'), api = 16)
+
def test_next_line(self) -> None:
input_file = io.StringIO(textwrap.dedent("""\
foo
@@ -382,8 +393,7 @@
# baz
qux
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, False)
+ parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
self.assertIsNone(parser.current_line)
self.assertEqual('foo', parser.next_line().strip())
@@ -409,8 +419,7 @@
VERSION_2 {
} VERSION_1; # asdf
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, False)
+ parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
parser.next_line()
version = parser.parse_version()
@@ -419,8 +428,8 @@
self.assertEqual(Tags.from_strs(['foo', 'bar']), version.tags)
expected_symbols = [
- symbolfile.Symbol('baz', Tags()),
- symbolfile.Symbol('qux', Tags.from_strs(['woodly', 'doodly'])),
+ Symbol('baz', Tags()),
+ Symbol('qux', Tags.from_strs(['woodly', 'doodly'])),
]
self.assertEqual(expected_symbols, version.symbols)
@@ -434,8 +443,7 @@
input_file = io.StringIO(textwrap.dedent("""\
VERSION_1 {
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, False)
+ parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
parser.next_line()
with self.assertRaises(symbolfile.ParseError):
parser.parse_version()
@@ -446,8 +454,7 @@
foo:
}
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, False)
+ parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
parser.next_line()
with self.assertRaises(symbolfile.ParseError):
parser.parse_version()
@@ -457,8 +464,7 @@
foo;
bar; # baz qux
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, False)
+ parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
parser.next_line()
symbol = parser.parse_symbol()
@@ -476,8 +482,7 @@
*;
};
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, False)
+ parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
parser.next_line()
with self.assertRaises(symbolfile.ParseError):
parser.parse_version()
@@ -489,8 +494,7 @@
*;
};
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, False)
+ parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
parser.next_line()
version = parser.parse_version()
self.assertEqual([], version.symbols)
@@ -501,8 +505,7 @@
foo
};
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, False)
+ parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
parser.next_line()
with self.assertRaises(symbolfile.ParseError):
parser.parse_version()
@@ -510,8 +513,7 @@
def test_parse_fails_invalid_input(self) -> None:
with self.assertRaises(symbolfile.ParseError):
input_file = io.StringIO('foo')
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'),
- 16, False, False)
+ parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
parser.parse()
def test_parse(self) -> None:
@@ -532,19 +534,18 @@
qwerty;
} VERSION_1;
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, False)
+ parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
versions = parser.parse()
expected = [
symbolfile.Version('VERSION_1', None, Tags(), [
- symbolfile.Symbol('foo', Tags()),
- symbolfile.Symbol('bar', Tags.from_strs(['baz'])),
+ Symbol('foo', Tags()),
+ Symbol('bar', Tags.from_strs(['baz'])),
]),
symbolfile.Version(
'VERSION_2', 'VERSION_1', Tags.from_strs(['wasd']), [
- symbolfile.Symbol('woodly', Tags()),
- symbolfile.Symbol('doodly', Tags.from_strs(['asdf'])),
+ Symbol('woodly', Tags()),
+ Symbol('doodly', Tags.from_strs(['asdf'])),
]),
]
@@ -559,8 +560,9 @@
qux; # apex
};
"""))
- parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
- False, True)
+ f = copy(self.filter)
+ f.llndk = True
+ parser = symbolfile.SymbolFileParser(input_file, {}, f)
parser.next_line()
version = parser.parse_version()
@@ -568,10 +570,10 @@
self.assertIsNone(version.base)
expected_symbols = [
- symbolfile.Symbol('foo', Tags()),
- symbolfile.Symbol('bar', Tags.from_strs(['llndk'])),
- symbolfile.Symbol('baz', Tags.from_strs(['llndk', 'apex'])),
- symbolfile.Symbol('qux', Tags.from_strs(['apex'])),
+ Symbol('foo', Tags()),
+ Symbol('bar', Tags.from_strs(['llndk'])),
+ Symbol('baz', Tags.from_strs(['llndk', 'apex'])),
+ Symbol('qux', Tags.from_strs(['apex'])),
]
self.assertEqual(expected_symbols, version.symbols)
diff --git a/cc/testing.go b/cc/testing.go
index ecdae8b..44a865d 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -20,6 +20,7 @@
"android/soong/android"
"android/soong/genrule"
+ "android/soong/multitree"
"android/soong/snapshot"
)
@@ -31,6 +32,8 @@
RegisterLibraryHeadersBuildComponents(ctx)
RegisterLibraryStubBuildComponents(ctx)
+ multitree.RegisterApiImportsModule(ctx)
+
ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
ctx.RegisterModuleType("cc_object", ObjectFactory)
ctx.RegisterModuleType("cc_genrule", GenRuleFactory)
@@ -73,7 +76,6 @@
nocrt: true,
system_shared_libs: [],
stl: "none",
- srcs: [""],
check_elf_files: false,
sanitize: {
never: true,
@@ -84,6 +86,7 @@
name: "libcompiler_rt-extras",
defaults: ["toolchain_libs_defaults"],
vendor_ramdisk_available: true,
+ srcs: [""],
}
cc_prebuilt_library_static {
@@ -93,11 +96,13 @@
vendor_available: true,
vendor_ramdisk_available: true,
native_bridge_supported: true,
+ srcs: [""],
}
cc_prebuilt_library_shared {
name: "libclang_rt.hwasan",
defaults: ["toolchain_libs_defaults"],
+ srcs: [""],
}
cc_prebuilt_library_static {
@@ -108,6 +113,7 @@
],
vendor_ramdisk_available: true,
native_bridge_supported: true,
+ srcs: [""],
}
cc_prebuilt_library_static {
@@ -116,17 +122,34 @@
"linux_bionic_supported",
"toolchain_libs_defaults",
],
+ srcs: [""],
}
// Needed for sanitizer
cc_prebuilt_library_shared {
name: "libclang_rt.ubsan_standalone",
defaults: ["toolchain_libs_defaults"],
+ srcs: [""],
}
cc_prebuilt_library_static {
name: "libclang_rt.ubsan_minimal",
defaults: ["toolchain_libs_defaults"],
+ host_supported: true,
+ target: {
+ android_arm64: {
+ srcs: ["libclang_rt.ubsan_minimal.android_arm64.a"],
+ },
+ android_arm: {
+ srcs: ["libclang_rt.ubsan_minimal.android_arm.a"],
+ },
+ linux_glibc_x86_64: {
+ srcs: ["libclang_rt.ubsan_minimal.x86_64.a"],
+ },
+ linux_glibc_x86: {
+ srcs: ["libclang_rt.ubsan_minimal.x86.a"],
+ },
+ },
}
cc_library {
@@ -174,7 +197,6 @@
native_coverage: false,
system_shared_libs: [],
stl: "none",
- notice: "custom_notice",
}
cc_library {
name: "libprofile-clang-extras",
@@ -185,7 +207,6 @@
native_coverage: false,
system_shared_libs: [],
stl: "none",
- notice: "custom_notice",
}
cc_library {
name: "libprofile-extras_ndk",
@@ -194,7 +215,6 @@
native_coverage: false,
system_shared_libs: [],
stl: "none",
- notice: "custom_notice",
sdk_version: "current",
}
cc_library {
@@ -204,7 +224,6 @@
native_coverage: false,
system_shared_libs: [],
stl: "none",
- notice: "custom_notice",
sdk_version: "current",
}
@@ -514,7 +533,7 @@
android.PrepareForTestWithAndroidBuildComponents,
android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("cc_fuzz", FuzzFactory)
+ ctx.RegisterModuleType("cc_fuzz", LibFuzzFactory)
ctx.RegisterModuleType("cc_test", TestFactory)
ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
@@ -546,6 +565,11 @@
"defaults/cc/common/crtend_so.c": nil,
"defaults/cc/common/crtend.c": nil,
"defaults/cc/common/crtbrand.c": nil,
+
+ "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil,
+ "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a": nil,
+ "defaults/cc/common/libclang_rt.ubsan_minimal.x86_64.a": nil,
+ "defaults/cc/common/libclang_rt.ubsan_minimal.x86.a": nil,
}.AddToFixture(),
// Place the default cc test modules that are common to all platforms in a location that will not
@@ -623,7 +647,7 @@
func CreateTestContext(config android.Config) *android.TestContext {
ctx := android.NewTestArchContext(config)
genrule.RegisterGenruleBuildComponents(ctx)
- ctx.RegisterModuleType("cc_fuzz", FuzzFactory)
+ ctx.RegisterModuleType("cc_fuzz", LibFuzzFactory)
ctx.RegisterModuleType("cc_test", TestFactory)
ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
diff --git a/cc/tidy.go b/cc/tidy.go
index ac1521b..6b5d572 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -15,6 +15,7 @@
package cc
import (
+ "fmt"
"path/filepath"
"regexp"
"strings"
@@ -62,6 +63,11 @@
return []interface{}{&tidy.Properties}
}
+// Set this const to true when all -warnings-as-errors in tidy_flags
+// are replaced with tidy_checks_as_errors.
+// Then, that old style usage will be obsolete and an error.
+const NoWarningsAsErrorsInTidyFlags = true
+
func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags {
CheckBadTidyFlags(ctx, "tidy_flags", tidy.Properties.Tidy_flags)
CheckBadTidyChecks(ctx, "tidy_checks", tidy.Properties.Tidy_checks)
@@ -144,61 +150,54 @@
tidyChecks += config.TidyChecksForDir(ctx.ModuleDir())
}
if len(tidy.Properties.Tidy_checks) > 0 {
- tidyChecks = tidyChecks + "," + strings.Join(esc(ctx, "tidy_checks",
- config.ClangRewriteTidyChecks(tidy.Properties.Tidy_checks)), ",")
+ // If Tidy_checks contains "-*", ignore all checks before "-*".
+ localChecks := tidy.Properties.Tidy_checks
+ ignoreGlobalChecks := false
+ for n, check := range tidy.Properties.Tidy_checks {
+ if check == "-*" {
+ ignoreGlobalChecks = true
+ localChecks = tidy.Properties.Tidy_checks[n:]
+ }
+ }
+ if ignoreGlobalChecks {
+ tidyChecks = "-checks=" + strings.Join(esc(ctx, "tidy_checks",
+ config.ClangRewriteTidyChecks(localChecks)), ",")
+ } else {
+ tidyChecks = tidyChecks + "," + strings.Join(esc(ctx, "tidy_checks",
+ config.ClangRewriteTidyChecks(localChecks)), ",")
+ }
}
+ tidyChecks = tidyChecks + config.TidyGlobalNoChecks()
if ctx.Windows() {
// https://b.corp.google.com/issues/120614316
// mingw32 has cert-dcl16-c warning in NO_ERROR,
// which is used in many Android files.
- tidyChecks = tidyChecks + ",-cert-dcl16-c"
+ tidyChecks += ",-cert-dcl16-c"
}
- // https://b.corp.google.com/issues/153464409
- // many local projects enable cert-* checks, which
- // trigger bugprone-reserved-identifier.
- tidyChecks = tidyChecks + ",-bugprone-reserved-identifier*,-cert-dcl51-cpp,-cert-dcl37-c"
- // http://b/153757728
- tidyChecks = tidyChecks + ",-readability-qualified-auto"
- // http://b/155034563
- tidyChecks = tidyChecks + ",-bugprone-signed-char-misuse"
- // http://b/155034972
- tidyChecks = tidyChecks + ",-bugprone-branch-clone"
- // http://b/193716442
- tidyChecks = tidyChecks + ",-bugprone-implicit-widening-of-multiplication-result"
- // Too many existing functions trigger this rule, and fixing it requires large code
- // refactoring. The cost of maintaining this tidy rule outweighs the benefit it brings.
- tidyChecks = tidyChecks + ",-bugprone-easily-swappable-parameters"
- // http://b/216364337 - TODO: Follow-up after compiler update to
- // disable or fix individual instances.
- tidyChecks = tidyChecks + ",-cert-err33-c"
+
flags.TidyFlags = append(flags.TidyFlags, tidyChecks)
- if ctx.Config().IsEnvTrue("WITH_TIDY") {
- // WITH_TIDY=1 enables clang-tidy globally. There could be many unexpected
- // warnings from new checks and many local tidy_checks_as_errors and
- // -warnings-as-errors can break a global build.
- // So allow all clang-tidy warnings.
- inserted := false
- for i, s := range flags.TidyFlags {
- if strings.Contains(s, "-warnings-as-errors=") {
- // clang-tidy accepts only one -warnings-as-errors
- // replace the old one
- re := regexp.MustCompile(`'?-?-warnings-as-errors=[^ ]* *`)
- newFlag := re.ReplaceAllString(s, "")
- if newFlag == "" {
- flags.TidyFlags[i] = "-warnings-as-errors=-*"
- } else {
- flags.TidyFlags[i] = newFlag + " -warnings-as-errors=-*"
- }
- inserted = true
- break
+ // Embedding -warnings-as-errors in tidy_flags is error-prone.
+ // It should be replaced with the tidy_checks_as_errors list.
+ for i, s := range flags.TidyFlags {
+ if strings.Contains(s, "-warnings-as-errors=") {
+ if NoWarningsAsErrorsInTidyFlags {
+ ctx.PropertyErrorf("tidy_flags", "should not contain "+s+"; use tidy_checks_as_errors instead.")
+ } else {
+ fmt.Printf("%s: warning: module %s's tidy_flags should not contain %s, which is replaced with -warnings-as-errors=-*; use tidy_checks_as_errors for your own as-error warnings instead.\n",
+ ctx.BlueprintsFile(), ctx.ModuleName(), s)
+ flags.TidyFlags[i] = "-warnings-as-errors=-*"
}
+ break // there is at most one -warnings-as-errors
}
- if !inserted {
- flags.TidyFlags = append(flags.TidyFlags, "-warnings-as-errors=-*")
- }
- } else if len(tidy.Properties.Tidy_checks_as_errors) > 0 {
- tidyChecksAsErrors := "-warnings-as-errors=" + strings.Join(esc(ctx, "tidy_checks_as_errors", tidy.Properties.Tidy_checks_as_errors), ",")
+ }
+ // Default clang-tidy flags does not contain -warning-as-errors.
+ // If a module has tidy_checks_as_errors, add the list to -warnings-as-errors
+ // and then append the TidyGlobalNoErrorChecks.
+ if len(tidy.Properties.Tidy_checks_as_errors) > 0 {
+ tidyChecksAsErrors := "-warnings-as-errors=" +
+ strings.Join(esc(ctx, "tidy_checks_as_errors", tidy.Properties.Tidy_checks_as_errors), ",") +
+ config.TidyGlobalNoErrorChecks()
flags.TidyFlags = append(flags.TidyFlags, tidyChecksAsErrors)
}
return flags
diff --git a/cc/tidy_test.go b/cc/tidy_test.go
index 339b302..7036ecb 100644
--- a/cc/tidy_test.go
+++ b/cc/tidy_test.go
@@ -16,11 +16,159 @@
import (
"fmt"
+ "strings"
"testing"
"android/soong/android"
)
+func TestTidyFlagsWarningsAsErrors(t *testing.T) {
+ // The "tidy_flags" property should not contain -warnings-as-errors.
+ type testCase struct {
+ libName, bp string
+ errorMsg string // a negative test; must have error message
+ flags []string // must have substrings in tidyFlags
+ noFlags []string // must not have substrings in tidyFlags
+ }
+
+ testCases := []testCase{
+ {
+ "libfoo1",
+ `cc_library_shared { // no warnings-as-errors, good tidy_flags
+ name: "libfoo1",
+ srcs: ["foo.c"],
+ tidy_flags: ["-header-filter=dir1/"],
+ }`,
+ "",
+ []string{"-header-filter=dir1/"},
+ []string{"-warnings-as-errors"},
+ },
+ {
+ "libfoo2",
+ `cc_library_shared { // good use of tidy_checks_as_errors
+ name: "libfoo2",
+ srcs: ["foo.c"],
+ tidy_checks_as_errors: ["xyz-*", "abc"],
+ }`,
+ "",
+ []string{
+ "-header-filter=^", // there is a default header filter
+ "-warnings-as-errors='xyz-*',abc,${config.TidyGlobalNoErrorChecks}",
+ },
+ []string{},
+ },
+ }
+ if NoWarningsAsErrorsInTidyFlags {
+ testCases = append(testCases, testCase{
+ "libfoo3",
+ `cc_library_shared { // bad use of -warnings-as-errors in tidy_flags
+ name: "libfoo3",
+ srcs: ["foo.c"],
+ tidy_flags: [
+ "-header-filters=.*",
+ "-warnings-as-errors=xyz-*",
+ ],
+ }`,
+ `module "libfoo3" .*: tidy_flags: should not contain .*;` +
+ ` use tidy_checks_as_errors instead`,
+ []string{},
+ []string{},
+ })
+ }
+ for _, test := range testCases {
+ if test.errorMsg != "" {
+ testCcError(t, test.errorMsg, test.bp)
+ continue
+ }
+ variant := "android_arm64_armv8-a_shared"
+ ctx := testCc(t, test.bp)
+ t.Run("caseTidyFlags", func(t *testing.T) {
+ flags := ctx.ModuleForTests(test.libName, variant).Rule("clangTidy").Args["tidyFlags"]
+ for _, flag := range test.flags {
+ if !strings.Contains(flags, flag) {
+ t.Errorf("tidyFlags %v for %s does not contain %s.", flags, test.libName, flag)
+ }
+ }
+ for _, flag := range test.noFlags {
+ if strings.Contains(flags, flag) {
+ t.Errorf("tidyFlags %v for %s should not contain %s.", flags, test.libName, flag)
+ }
+ }
+ })
+ }
+}
+
+func TestTidyChecks(t *testing.T) {
+ // The "tidy_checks" property defines additional checks appended
+ // to global default. But there are some checks disabled after
+ // the local tidy_checks.
+ bp := `
+ cc_library_shared { // has global checks + extraGlobalChecks
+ name: "libfoo_1",
+ srcs: ["foo.c"],
+ }
+ cc_library_shared { // has only local checks + extraGlobalChecks
+ name: "libfoo_2",
+ srcs: ["foo.c"],
+ tidy_checks: ["-*", "xyz-*"],
+ }
+ cc_library_shared { // has global checks + local checks + extraGlobalChecks
+ name: "libfoo_3",
+ srcs: ["foo.c"],
+ tidy_checks: ["-abc*", "xyz-*", "mycheck"],
+ }
+ cc_library_shared { // has only local checks after "-*" + extraGlobalChecks
+ name: "libfoo_4",
+ srcs: ["foo.c"],
+ tidy_checks: ["-abc*", "xyz-*", "mycheck", "-*", "xyz-*"],
+ }`
+ ctx := testCc(t, bp)
+
+ globalChecks := "-checks=${config.TidyDefaultGlobalChecks},"
+ firstXyzChecks := "-checks='-*','xyz-*',"
+ localXyzChecks := "'-*','xyz-*'"
+ localAbcChecks := "'-abc*','xyz-*',mycheck"
+ extraGlobalChecks := ",${config.TidyGlobalNoChecks}"
+ testCases := []struct {
+ libNumber int // 1,2,3,...
+ checks []string // must have substrings in -checks
+ noChecks []string // must not have substrings in -checks
+ }{
+ {1, []string{globalChecks, extraGlobalChecks}, []string{localXyzChecks, localAbcChecks}},
+ {2, []string{firstXyzChecks, extraGlobalChecks}, []string{globalChecks, localAbcChecks}},
+ {3, []string{globalChecks, localAbcChecks, extraGlobalChecks}, []string{localXyzChecks}},
+ {4, []string{firstXyzChecks, extraGlobalChecks}, []string{globalChecks, localAbcChecks}},
+ }
+ t.Run("caseTidyChecks", func(t *testing.T) {
+ variant := "android_arm64_armv8-a_shared"
+ for _, test := range testCases {
+ libName := fmt.Sprintf("libfoo_%d", test.libNumber)
+ flags := ctx.ModuleForTests(libName, variant).Rule("clangTidy").Args["tidyFlags"]
+ splitFlags := strings.Split(flags, " ")
+ foundCheckFlag := false
+ for _, flag := range splitFlags {
+ if strings.HasPrefix(flag, "-checks=") {
+ foundCheckFlag = true
+ for _, check := range test.checks {
+ if !strings.Contains(flag, check) {
+ t.Errorf("tidyFlags for %s does not contain %s.", libName, check)
+ }
+ }
+ for _, check := range test.noChecks {
+ if strings.Contains(flag, check) {
+ t.Errorf("tidyFlags for %s should not contain %s.", libName, check)
+ }
+ }
+ break
+ }
+ }
+ if !foundCheckFlag {
+ t.Errorf("tidyFlags for %s does not contain -checks=.", libName)
+ }
+ }
+ })
+}
+
func TestWithTidy(t *testing.T) {
// When WITH_TIDY=1 or (ALLOW_LOCAL_TIDY_TRUE=1 and local tidy:true)
// a C++ library should depend on .tidy files.
diff --git a/cc/vndk.go b/cc/vndk.go
index bf6148b..4cd4d42 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -671,12 +671,8 @@
snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
configsDir := filepath.Join(snapshotArchDir, "configs")
- noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
includeDir := filepath.Join(snapshotArchDir, "include")
- // set of notice files copied.
- noticeBuilt := make(map[string]bool)
-
// paths of VNDK modules for GPL license checking
modulePaths := make(map[string]string)
@@ -762,16 +758,6 @@
moduleNames[stem] = ctx.ModuleName(m)
modulePaths[stem] = ctx.ModuleDir(m)
- if len(m.NoticeFiles()) > 0 {
- noticeName := stem + ".txt"
- // skip already copied notice file
- if _, ok := noticeBuilt[noticeName]; !ok {
- noticeBuilt[noticeName] = true
- snapshotOutputs = append(snapshotOutputs, combineNoticesRule(
- ctx, m.NoticeFiles(), filepath.Join(noticeDir, noticeName)))
- }
- }
-
if ctx.Config().VndkSnapshotBuildArtifacts() {
headers = append(headers, m.SnapshotHeaders()...)
}
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index f8844fc..d4a57bf 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -824,6 +824,7 @@
var regen string
var pom2build bool
+ var prepend string
flag.Var(&excludes, "exclude", "Exclude module")
flag.Var(&extraStaticLibs, "extra-static-libs", "Extra static dependencies needed when depending on a module")
@@ -839,6 +840,7 @@
flag.BoolVar(&jetifier, "jetifier", false, "Sets jetifier: true on all modules")
flag.StringVar(®en, "regen", "", "Rewrite specified file")
flag.BoolVar(&pom2build, "pom2build", false, "If true, will generate a Bazel BUILD file *instead* of a .bp file")
+ flag.StringVar(&prepend, "prepend", "", "Path to a file containing text to insert at the beginning of the generated build file")
flag.Parse()
if regen != "" {
@@ -965,6 +967,15 @@
fmt.Fprintln(buf, commentString, "Automatically generated with:")
fmt.Fprintln(buf, commentString, "pom2bp", strings.Join(proptools.ShellEscapeList(os.Args[1:]), " "))
+ if prepend != "" {
+ contents, err := ioutil.ReadFile(prepend)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "Error reading", prepend, err)
+ os.Exit(1)
+ }
+ fmt.Fprintln(buf, string(contents))
+ }
+
depsTemplate := bpDepsTemplate
template := bpTemplate
if pom2build {
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index a51db36..53422cd 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -139,7 +139,7 @@
bazelHook := func() error {
ctx.EventHandler.Begin("bazel")
defer ctx.EventHandler.End("bazel")
- return configuration.BazelContext.InvokeBazel()
+ return configuration.BazelContext.InvokeBazel(configuration)
}
ctx.SetBeforePrepareBuildActionsHook(bazelHook)
@@ -166,8 +166,7 @@
touch(shared.JoinPath(topDir, queryviewMarker))
}
-func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler) {
- metricsDir := configuration.Getenv("LOG_DIR")
+func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler, metricsDir string) {
if len(metricsDir) < 1 {
fmt.Fprintf(os.Stderr, "\nMissing required env var for generating soong metrics: LOG_DIR\n")
os.Exit(1)
@@ -221,7 +220,7 @@
// doChosenActivity runs Soong for a specific activity, like bp2build, queryview
// or the actual Soong build for the build.ninja file. Returns the top level
// output file of the specific activity.
-func doChosenActivity(configuration android.Config, extraNinjaDeps []string) string {
+func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string, logDir string) string {
mixedModeBuild := configuration.BazelContext.BazelEnabled()
generateBazelWorkspace := bp2buildMarker != ""
generateQueryView := bazelQueryViewDir != ""
@@ -237,7 +236,6 @@
blueprintArgs := cmdlineArgs
- ctx := newContext(configuration)
if mixedModeBuild {
runMixedModeBuild(configuration, ctx, extraNinjaDeps)
} else {
@@ -285,7 +283,6 @@
}
}
- writeMetrics(configuration, *ctx.EventHandler)
return cmdlineArgs.OutFile
}
@@ -341,7 +338,17 @@
extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.SoongOutDir(), "always_rerun_for_delve"))
}
- finalOutputFile := doChosenActivity(configuration, extraNinjaDeps)
+ // Bypass configuration.Getenv, as LOG_DIR does not need to be dependency tracked. By definition, it will
+ // change between every CI build, so tracking it would require re-running Soong for every build.
+ logDir := availableEnv["LOG_DIR"]
+
+ ctx := newContext(configuration)
+ ctx.EventHandler.Begin("soong_build")
+
+ finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps, logDir)
+
+ ctx.EventHandler.End("soong_build")
+ writeMetrics(configuration, *ctx.EventHandler, logDir)
writeUsedEnvironmentFile(configuration, finalOutputFile)
}
@@ -443,6 +450,8 @@
// FIXME: 'autotest_lib' is a symlink back to external/autotest, and this causes an infinite symlink expansion error for Bazel
excludes = append(excludes, "external/autotest/venv/autotest_lib")
+ excludes = append(excludes, "external/autotest/autotest_lib")
+ excludes = append(excludes, "external/autotest/client/autotest_lib/client")
// FIXME: The external/google-fruit/extras/bazel_root/third_party/fruit dir is poison
// It contains several symlinks back to real source dirs, and those source dirs contain BUILD files we want to ignore
@@ -475,93 +484,95 @@
// Bazel BUILD files instead of Ninja files.
func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
eventHandler := metrics.EventHandler{}
- eventHandler.Begin("bp2build")
+ var metrics bp2build.CodegenMetrics
+ eventHandler.Do("bp2build", func() {
- // Register an alternate set of singletons and mutators for bazel
- // conversion for Bazel conversion.
- bp2buildCtx := android.NewContext(configuration)
+ // Register an alternate set of singletons and mutators for bazel
+ // conversion for Bazel conversion.
+ bp2buildCtx := android.NewContext(configuration)
- // Soong internals like LoadHooks behave differently when running as
- // bp2build. This is the bit to differentiate between Soong-as-Soong and
- // Soong-as-bp2build.
- bp2buildCtx.SetRunningAsBp2build()
+ // Soong internals like LoadHooks behave differently when running as
+ // bp2build. This is the bit to differentiate between Soong-as-Soong and
+ // Soong-as-bp2build.
+ bp2buildCtx.SetRunningAsBp2build()
- // Propagate "allow misssing dependencies" bit. This is normally set in
- // newContext(), but we create bp2buildCtx without calling that method.
- bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
- bp2buildCtx.SetNameInterface(newNameResolver(configuration))
- bp2buildCtx.RegisterForBazelConversion()
+ // Propagate "allow misssing dependencies" bit. This is normally set in
+ // newContext(), but we create bp2buildCtx without calling that method.
+ bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
+ bp2buildCtx.SetNameInterface(newNameResolver(configuration))
+ bp2buildCtx.RegisterForBazelConversion()
- // The bp2build process is a purely functional process that only depends on
- // Android.bp files. It must not depend on the values of per-build product
- // configurations or variables, since those will generate different BUILD
- // files based on how the user has configured their tree.
- bp2buildCtx.SetModuleListFile(cmdlineArgs.ModuleListFile)
- modulePaths, err := bp2buildCtx.ListModulePaths(".")
- if err != nil {
- panic(err)
- }
+ // The bp2build process is a purely functional process that only depends on
+ // Android.bp files. It must not depend on the values of per-build product
+ // configurations or variables, since those will generate different BUILD
+ // files based on how the user has configured their tree.
+ bp2buildCtx.SetModuleListFile(cmdlineArgs.ModuleListFile)
+ modulePaths, err := bp2buildCtx.ListModulePaths(".")
+ if err != nil {
+ panic(err)
+ }
- extraNinjaDeps = append(extraNinjaDeps, modulePaths...)
+ extraNinjaDeps = append(extraNinjaDeps, modulePaths...)
- // Run the loading and analysis pipeline to prepare the graph of regular
- // Modules parsed from Android.bp files, and the BazelTargetModules mapped
- // from the regular Modules.
- blueprintArgs := cmdlineArgs
- ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bootstrap.StopBeforePrepareBuildActions, bp2buildCtx.Context, configuration)
- ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
+ // Run the loading and analysis pipeline to prepare the graph of regular
+ // Modules parsed from Android.bp files, and the BazelTargetModules mapped
+ // from the regular Modules.
+ blueprintArgs := cmdlineArgs
+ ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bootstrap.StopBeforePrepareBuildActions, bp2buildCtx.Context, configuration)
+ ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
- globListFiles := writeBuildGlobsNinjaFile(bp2buildCtx, configuration.SoongOutDir(), configuration)
- ninjaDeps = append(ninjaDeps, globListFiles...)
+ globListFiles := writeBuildGlobsNinjaFile(bp2buildCtx, configuration.SoongOutDir(), configuration)
+ ninjaDeps = append(ninjaDeps, globListFiles...)
- // Run the code-generation phase to convert BazelTargetModules to BUILD files
- // and print conversion metrics to the user.
- codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
- metrics := bp2build.Codegen(codegenContext)
+ // Run the code-generation phase to convert BazelTargetModules to BUILD files
+ // and print conversion metrics to the user.
+ codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
+ metrics = bp2build.Codegen(codegenContext)
- generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build")
- workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace")
+ generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build")
+ workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace")
- excludes := []string{
- "bazel-bin",
- "bazel-genfiles",
- "bazel-out",
- "bazel-testlogs",
- "bazel-" + filepath.Base(topDir),
- }
+ excludes := []string{
+ "bazel-bin",
+ "bazel-genfiles",
+ "bazel-out",
+ "bazel-testlogs",
+ "bazel-" + filepath.Base(topDir),
+ }
- if outDir[0] != '/' {
- excludes = append(excludes, outDir)
- }
+ if outDir[0] != '/' {
+ excludes = append(excludes, outDir)
+ }
- existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err)
- os.Exit(1)
- }
+ existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err)
+ os.Exit(1)
+ }
- pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE"))
- excludes = append(excludes, pathsToIgnoredBuildFiles...)
+ pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE"))
+ excludes = append(excludes, pathsToIgnoredBuildFiles...)
- excludes = append(excludes, getTemporaryExcludes()...)
+ excludes = append(excludes, getTemporaryExcludes()...)
- symlinkForestDeps := bp2build.PlantSymlinkForest(
- topDir, workspaceRoot, generatedRoot, ".", excludes)
+ symlinkForestDeps := bp2build.PlantSymlinkForest(
+ configuration, topDir, workspaceRoot, generatedRoot, ".", excludes)
- ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
- ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
+ ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
+ ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
- writeDepFile(bp2buildMarker, eventHandler, ninjaDeps)
+ writeDepFile(bp2buildMarker, eventHandler, ninjaDeps)
- // Create an empty bp2build marker file.
- touch(shared.JoinPath(topDir, bp2buildMarker))
-
- eventHandler.End("bp2build")
+ // Create an empty bp2build marker file.
+ touch(shared.JoinPath(topDir, bp2buildMarker))
+ })
// Only report metrics when in bp2build mode. The metrics aren't relevant
// for queryview, since that's a total repo-wide conversion and there's a
// 1:1 mapping for each module.
- metrics.Print()
+ if configuration.IsEnvTrue("BP2BUILD_VERBOSE") {
+ metrics.Print()
+ }
writeBp2BuildMetrics(&metrics, configuration, eventHandler)
}
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index d63ded5..983dbf0 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -32,7 +32,8 @@
panic(err)
}
- filesToWrite := bp2build.CreateBazelFiles(ruleShims, res.BuildDirToTargets(), bp2build.QueryView)
+ filesToWrite := bp2build.CreateBazelFiles(ctx.Config(), ruleShims, res.BuildDirToTargets(),
+ bp2build.QueryView)
for _, f := range filesToWrite {
if err := writeReadOnlyFile(bazelQueryViewDir, f); err != nil {
return err
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index a03a86a..cb85634 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -66,11 +66,9 @@
{
flag: "--make-mode",
description: "build the modules by the target name (i.e. soong_docs)",
- config: func(ctx build.Context, args ...string) build.Config {
- return build.NewConfig(ctx, args...)
- },
- stdio: stdio,
- run: runMake,
+ config: build.NewConfig,
+ stdio: stdio,
+ run: runMake,
}, {
flag: "--dumpvar-mode",
description: "print the value of the legacy make variable VAR to stdout",
@@ -114,7 +112,7 @@
// Main execution of soong_ui. The command format is as follows:
//
-// soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
+// soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
//
// Command is the type of soong_ui execution. Only one type of
// execution is specified. The args are specific to the command.
@@ -221,6 +219,7 @@
}
defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, files...)
defer met.Dump(soongMetricsFile)
+ defer build.CheckProdCreds(buildCtx, config)
}
// Read the time at the starting point.
@@ -269,6 +268,8 @@
func dumpVar(ctx build.Context, config build.Config, args []string, _ string) {
flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
+ flags.SetOutput(ctx.Writer)
+
flags.Usage = func() {
fmt.Fprintf(ctx.Writer, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
fmt.Fprintln(ctx.Writer, "In dumpvar mode, print the value of the legacy make variable VAR to stdout")
@@ -319,6 +320,8 @@
func dumpVars(ctx build.Context, config build.Config, args []string, _ string) {
flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
+ flags.SetOutput(ctx.Writer)
+
flags.Usage = func() {
fmt.Fprintf(ctx.Writer, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
fmt.Fprintln(ctx.Writer, "In dumpvars mode, dump the values of one or more legacy make variables, in")
@@ -402,6 +405,8 @@
func buildActionConfig(ctx build.Context, args ...string) build.Config {
flags := flag.NewFlagSet("build-mode", flag.ContinueOnError)
+ flags.SetOutput(ctx.Writer)
+
flags.Usage = func() {
fmt.Fprintf(ctx.Writer, "usage: %s --build-mode --dir=<path> <build action> [<build arg 1> <build arg 2> ...]\n\n", os.Args[0])
fmt.Fprintln(ctx.Writer, "In build mode, build the set of modules based on the specified build")
@@ -454,21 +459,32 @@
const numBuildActionFlags = 2
if len(args) < numBuildActionFlags {
flags.Usage()
- ctx.Fatalln("Improper build action arguments.")
+ ctx.Fatalln("Improper build action arguments: too few arguments")
}
- flags.Parse(args[0:numBuildActionFlags])
+ parseError := flags.Parse(args[0:numBuildActionFlags])
// The next block of code is to validate that exactly one build action is set and the dir flag
// is specified.
- buildActionCount := 0
+ buildActionFound := false
var buildAction build.BuildAction
- for _, flag := range buildActionFlags {
- if flag.set {
- buildActionCount++
- buildAction = flag.action
+ for _, f := range buildActionFlags {
+ if f.set {
+ if buildActionFound {
+ if parseError == nil {
+ //otherwise Parse() already called Usage()
+ flags.Usage()
+ }
+ ctx.Fatalf("Build action already specified, omit: --%s\n", f.name)
+ }
+ buildActionFound = true
+ buildAction = f.action
}
}
- if buildActionCount != 1 {
+ if !buildActionFound {
+ if parseError == nil {
+ //otherwise Parse() already called Usage()
+ flags.Usage()
+ }
ctx.Fatalln("Build action not defined.")
}
if *dir == "" {
@@ -490,11 +506,7 @@
fmt.Fprintln(writer, "!")
fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files")
fmt.Fprintln(writer, "")
- select {
- case <-time.After(5 * time.Second):
- case <-ctx.Done():
- return
- }
+ ctx.Fatal("done")
}
if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
@@ -514,8 +526,16 @@
// getCommand finds the appropriate command based on args[1] flag. args[0]
// is the soong_ui filename.
func getCommand(args []string) (*command, []string, error) {
+ listFlags := func() []string {
+ flags := make([]string, len(commands))
+ for i, c := range commands {
+ flags[i] = c.flag
+ }
+ return flags
+ }
+
if len(args) < 2 {
- return nil, nil, fmt.Errorf("Too few arguments: %q", args)
+ return nil, nil, fmt.Errorf("Too few arguments: %q\nUse one of these: %q", args, listFlags())
}
for _, c := range commands {
@@ -523,13 +543,7 @@
return &c, args[2:], nil
}
}
-
- // command not found
- flags := make([]string, len(commands))
- for i, c := range commands {
- flags[i] = c.flag
- }
- return nil, nil, fmt.Errorf("Command not found: %q\nDid you mean one of these: %q", args, flags)
+ return nil, nil, fmt.Errorf("Command not found: %q\nDid you mean one of these: %q", args[1], listFlags())
}
// For Bazel support, this moves files and directories from e.g. out/dist/$f to DIST_DIR/$f if necessary.
diff --git a/compliance/copy_license_metadata/Android.bp b/compliance/copy_license_metadata/Android.bp
new file mode 100644
index 0000000..83019eb
--- /dev/null
+++ b/compliance/copy_license_metadata/Android.bp
@@ -0,0 +1,30 @@
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+ name: "copy_license_metadata",
+ srcs: [
+ "copy_license_metadata.go",
+ ],
+ deps: [
+ "license_metadata_proto",
+ "golang-protobuf-proto",
+ "golang-protobuf-encoding-prototext",
+ "soong-response",
+ ],
+}
diff --git a/compliance/copy_license_metadata/copy_license_metadata.go b/compliance/copy_license_metadata/copy_license_metadata.go
new file mode 100644
index 0000000..36b9489
--- /dev/null
+++ b/compliance/copy_license_metadata/copy_license_metadata.go
@@ -0,0 +1,144 @@
+// 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 main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ "google.golang.org/protobuf/encoding/prototext"
+ "google.golang.org/protobuf/proto"
+
+ "android/soong/compliance/license_metadata_proto"
+ "android/soong/response"
+)
+
+func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
+ var f multiString
+ flags.Var(&f, name, usage)
+ return &f
+}
+
+type multiString []string
+
+func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
+func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
+
+func main() {
+ var expandedArgs []string
+ for _, arg := range os.Args[1:] {
+ if strings.HasPrefix(arg, "@") {
+ f, err := os.Open(strings.TrimPrefix(arg, "@"))
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(1)
+ }
+
+ respArgs, err := response.ReadRspFile(f)
+ f.Close()
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(1)
+ }
+ expandedArgs = append(expandedArgs, respArgs...)
+ } else {
+ expandedArgs = append(expandedArgs, arg)
+ }
+ }
+
+ flags := flag.NewFlagSet("flags", flag.ExitOnError)
+
+ installed := flags.String("i", "", "installed target")
+ sources := newMultiString(flags, "s", "source (input) file")
+ dep := flags.String("d", "", "license metadata file dependency")
+ outFile := flags.String("o", "", "output file")
+
+ flags.Parse(expandedArgs)
+
+ if len(*dep) == 0 || len(*installed) == 0 || len(*sources) == 0 {
+ flags.Usage()
+ if len(*dep) == 0 {
+ fmt.Fprintf(os.Stderr, "source license metadata (-d flag) required\n")
+ }
+ if len(*sources) == 0 {
+ fmt.Fprintf(os.Stderr, "source copy (-s flag required\n")
+ }
+ if len(*installed) == 0 {
+ fmt.Fprintf(os.Stderr, "installed copy (-i flag) required\n")
+ }
+ os.Exit(1)
+ }
+
+ src_metadata := license_metadata_proto.LicenseMetadata{}
+ err := readMetadata(*dep, &src_metadata)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
+ os.Exit(2)
+ }
+
+ metadata := src_metadata
+ metadata.Built = nil
+ metadata.InstallMap = nil
+ metadata.Installed = []string{*installed}
+ metadata.Sources = *sources
+ metadata.Deps = []*license_metadata_proto.AnnotatedDependency{&license_metadata_proto.AnnotatedDependency{
+ File: proto.String(*dep),
+ Annotations: []string{"static"},
+ }}
+
+ err = writeMetadata(*outFile, &metadata)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
+ os.Exit(2)
+ }
+}
+
+func readMetadata(file string, metadata *license_metadata_proto.LicenseMetadata) error {
+ if file == "" {
+ return fmt.Errorf("source metadata file (-d) required")
+ }
+ buf, err := ioutil.ReadFile(file)
+ if err != nil {
+ return fmt.Errorf("error reading textproto %q: %w", file, err)
+ }
+
+ err = prototext.Unmarshal(buf, metadata)
+ if err != nil {
+ return fmt.Errorf("error unmarshalling textproto: %w", err)
+ }
+
+ return nil
+}
+
+func writeMetadata(file string, metadata *license_metadata_proto.LicenseMetadata) error {
+ buf, err := prototext.MarshalOptions{Multiline: true}.Marshal(metadata)
+ if err != nil {
+ return fmt.Errorf("error marshalling textproto: %w", err)
+ }
+
+ if file != "" {
+ err = ioutil.WriteFile(file, buf, 0666)
+ if err != nil {
+ return fmt.Errorf("error writing textproto %q: %w", file, err)
+ }
+ } else {
+ _, _ = os.Stdout.Write(buf)
+ }
+
+ return nil
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index ab9e418..eefda19 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -250,8 +250,9 @@
}
type globalConfigAndRaw struct {
- global *GlobalConfig
- data []byte
+ global *GlobalConfig
+ data []byte
+ pathErrors []error
}
// GetGlobalConfig returns the global dexpreopt.config that's created in the
@@ -272,16 +273,26 @@
var globalConfigOnceKey = android.NewOnceKey("DexpreoptGlobalConfig")
var testGlobalConfigOnceKey = android.NewOnceKey("TestDexpreoptGlobalConfig")
+type pathContextErrorCollector struct {
+ android.PathContext
+ errors []error
+}
+
+func (p *pathContextErrorCollector) Errorf(format string, args ...interface{}) {
+ p.errors = append(p.errors, fmt.Errorf(format, args...))
+}
+
func getGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw {
- return ctx.Config().Once(globalConfigOnceKey, func() interface{} {
+ config := ctx.Config().Once(globalConfigOnceKey, func() interface{} {
if data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil {
panic(err)
} else if data != nil {
- globalConfig, err := ParseGlobalConfig(ctx, data)
+ pathErrorCollectorCtx := &pathContextErrorCollector{PathContext: ctx}
+ globalConfig, err := ParseGlobalConfig(pathErrorCollectorCtx, data)
if err != nil {
panic(err)
}
- return globalConfigAndRaw{globalConfig, data}
+ return globalConfigAndRaw{globalConfig, data, pathErrorCollectorCtx.errors}
}
// No global config filename set, see if there is a test config set
@@ -291,16 +302,35 @@
DisablePreopt: true,
DisablePreoptBootImages: true,
DisableGenerateProfile: true,
- }, nil}
+ }, nil, nil}
})
}).(globalConfigAndRaw)
+
+ // Avoid non-deterministic errors by reporting cached path errors on all callers.
+ for _, err := range config.pathErrors {
+ if ctx.Config().AllowMissingDependencies() {
+ // When AllowMissingDependencies it set, report errors through AddMissingDependencies.
+ // If AddMissingDependencies doesn't exist on the current context (for example when
+ // called with a SingletonContext), just swallow the errors since there is no way to
+ // report them.
+ if missingDepsCtx, ok := ctx.(interface {
+ AddMissingDependencies(missingDeps []string)
+ }); ok {
+ missingDepsCtx.AddMissingDependencies([]string{err.Error()})
+ }
+ } else {
+ android.ReportPathErrorf(ctx, "%w", err)
+ }
+ }
+
+ return config
}
// SetTestGlobalConfig sets a GlobalConfig that future calls to GetGlobalConfig
// will return. It must be called before the first call to GetGlobalConfig for
// the config.
func SetTestGlobalConfig(config android.Config, globalConfig *GlobalConfig) {
- config.Once(testGlobalConfigOnceKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} })
+ config.Once(testGlobalConfigOnceKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil, nil} })
}
// This struct is required to convert ModuleConfig from/to JSON.
@@ -492,7 +522,7 @@
return &GlobalSoongConfig{
Profman: ctx.Config().HostToolPath(ctx, "profman"),
Dex2oat: dex2oatPathFromDep(ctx),
- Aapt: ctx.Config().HostToolPath(ctx, "aapt"),
+ Aapt: ctx.Config().HostToolPath(ctx, "aapt2"),
SoongZip: ctx.Config().HostToolPath(ctx, "soong_zip"),
Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"),
ManifestCheck: ctx.Config().HostToolPath(ctx, "manifest_check"),
@@ -694,7 +724,7 @@
return &GlobalSoongConfig{
Profman: android.PathForTesting("profman"),
Dex2oat: android.PathForTesting("dex2oat"),
- Aapt: android.PathForTesting("aapt"),
+ Aapt: android.PathForTesting("aapt2"),
SoongZip: android.PathForTesting("soong_zip"),
Zip2zip: android.PathForTesting("zip2zip"),
ManifestCheck: android.PathForTesting("manifest_check"),
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index de139c4..d8011d6 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -394,10 +394,14 @@
if !android.PrefixInList(preoptFlags, "--compiler-filter=") {
var compilerFilter string
if systemServerJars.ContainsJar(module.Name) {
- // Jars of system server, use the product option if it is set, speed otherwise.
if global.SystemServerCompilerFilter != "" {
+ // Use the product option if it is set.
compilerFilter = global.SystemServerCompilerFilter
+ } else if profile != nil {
+ // Use "speed-profile" for system server jars that have a profile.
+ compilerFilter = "speed-profile"
} else {
+ // Use "speed" for system server jars that do not have a profile.
compilerFilter = "speed"
}
} else if contains(global.SpeedApps, module.Name) || contains(global.SystemServerApps, module.Name) {
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index 857dfa7..dfcd405 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -12,6 +12,7 @@
"soong-linkerconfig",
],
srcs: [
+ "avb_add_hash_footer.go",
"bootimg.go",
"filesystem.go",
"logical_partition.go",
diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go
new file mode 100644
index 0000000..af3bdbe
--- /dev/null
+++ b/filesystem/avb_add_hash_footer.go
@@ -0,0 +1,149 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package filesystem
+
+import (
+ "fmt"
+ "strconv"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("avb_add_hash_footer", avbAddHashFooterFactory)
+}
+
+type avbAddHashFooter struct {
+ android.ModuleBase
+
+ properties avbAddHashFooterProperties
+
+ output android.OutputPath
+ installDir android.InstallPath
+}
+
+type avbAddHashFooterProperties struct {
+ // Source file of this image. Can reference a genrule type module with the ":module" syntax.
+ Src *string `android:"path,arch_variant"`
+
+ // Set the name of the output. Defaults to <module_name>.img.
+ Filename *string
+
+ // Name of the image partition. Defaults to the name of this module.
+ Partition_name *string
+
+ // Size of the partition. Defaults to dynamically calculating the size.
+ Partition_size *int64
+
+ // Path to the private key that avbtool will use to sign this image.
+ Private_key *string `android:"path"`
+
+ // Algorithm that avbtool will use to sign this image. Default is SHA256_RSA4096.
+ Algorithm *string
+
+ // The salt in hex. Required for reproducible builds.
+ Salt *string
+}
+
+// The AVB footer adds verification information to the image.
+func avbAddHashFooterFactory() android.Module {
+ module := &avbAddHashFooter{}
+ module.AddProperties(&module.properties)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
+
+func (a *avbAddHashFooter) installFileName() string {
+ return proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".img")
+}
+
+func (a *avbAddHashFooter) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ builder := android.NewRuleBuilder(pctx, ctx)
+
+ if a.properties.Src == nil {
+ ctx.PropertyErrorf("src", "missing source file")
+ return
+ }
+ input := android.PathForModuleSrc(ctx, proptools.String(a.properties.Src))
+ a.output = android.PathForModuleOut(ctx, a.installFileName()).OutputPath
+ builder.Command().Text("cp").Input(input).Output(a.output)
+
+ cmd := builder.Command().BuiltTool("avbtool").Text("add_hash_footer")
+
+ partition_name := proptools.StringDefault(a.properties.Partition_name, a.BaseModuleName())
+ cmd.FlagWithArg("--partition_name ", partition_name)
+
+ if a.properties.Partition_size == nil {
+ cmd.Flag("--dynamic_partition_size")
+ } else {
+ partition_size := proptools.Int(a.properties.Partition_size)
+ cmd.FlagWithArg("--partition_size ", strconv.Itoa(partition_size))
+ }
+
+ key := android.PathForModuleSrc(ctx, proptools.String(a.properties.Private_key))
+ cmd.FlagWithInput("--key ", key)
+
+ algorithm := proptools.StringDefault(a.properties.Algorithm, "SHA256_RSA4096")
+ cmd.FlagWithArg("--algorithm ", algorithm)
+
+ if a.properties.Salt == nil {
+ ctx.PropertyErrorf("salt", "missing salt value")
+ return
+ }
+ cmd.FlagWithArg("--salt ", proptools.String(a.properties.Salt))
+
+ cmd.FlagWithOutput("--image ", a.output)
+
+ builder.Build("avbAddHashFooter", fmt.Sprintf("avbAddHashFooter %s", ctx.ModuleName()))
+
+ a.installDir = android.PathForModuleInstall(ctx, "etc")
+ ctx.InstallFile(a.installDir, a.installFileName(), a.output)
+}
+
+var _ android.AndroidMkEntriesProvider = (*avbAddHashFooter)(nil)
+
+// Implements android.AndroidMkEntriesProvider
+func (a *avbAddHashFooter) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(a.output),
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", a.installDir.String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", a.installFileName())
+ },
+ },
+ }}
+}
+
+var _ Filesystem = (*avbAddHashFooter)(nil)
+
+func (a *avbAddHashFooter) OutputPath() android.Path {
+ return a.output
+}
+
+func (a *avbAddHashFooter) SignedOutputPath() android.Path {
+ return a.OutputPath() // always signed
+}
+
+// TODO(b/185115783): remove when not needed as input to a prebuilt_etc rule
+var _ android.SourceFileProducer = (*avbAddHashFooter)(nil)
+
+// Implements android.SourceFileProducer
+func (a *avbAddHashFooter) Srcs() android.Paths {
+ return append(android.Paths{}, a.output)
+}
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 700cdf0..c8cd21b 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -18,6 +18,7 @@
import (
"encoding/json"
+ "fmt"
"sort"
"strings"
@@ -29,11 +30,20 @@
type Lang string
const (
- Cc Lang = ""
+ Cc Lang = "cc"
Rust Lang = "rust"
Java Lang = "java"
)
+type Framework string
+
+const (
+ AFL Framework = "afl"
+ LibFuzzer Framework = "libfuzzer"
+ Jazzer Framework = "jazzer"
+ UnknownFramework Framework = "unknownframework"
+)
+
var BoolDefault = proptools.BoolDefault
type FuzzModule struct {
@@ -59,9 +69,65 @@
Dir string
}
+type PrivilegedLevel string
+
+const (
+ // Environment with the most minimal permissions.
+ Constrained PrivilegedLevel = "Constrained"
+ // Typical execution environment running unprivileged code.
+ Unprivileged = "Unprivileged"
+ // May have access to elevated permissions.
+ Privileged = "Privileged"
+ // Trusted computing base.
+ Tcb = "TCB"
+ // Bootloader chain.
+ Bootloader = "Bootloader"
+ // Tusted execution environment.
+ Tee = "Tee"
+ // Secure enclave.
+ Se = "Se"
+ // Other.
+ Other = "Other"
+)
+
+func IsValidConfig(fuzzModule FuzzPackagedModule, moduleName string) bool {
+ var config = fuzzModule.FuzzProperties.Fuzz_config
+ if config != nil {
+ var level = PrivilegedLevel(config.Privilege_level)
+ if level != "" {
+ switch level {
+ case Constrained, Unprivileged, Privileged, Tcb, Bootloader, Tee, Se, Other:
+ return true
+ }
+ panic(fmt.Errorf("Invalid privileged level in fuzz config in %s", moduleName))
+ }
+ return true
+ } else {
+ return false
+ }
+}
+
type FuzzConfig struct {
// Email address of people to CC on bugs or contact about this fuzz target.
Cc []string `json:"cc,omitempty"`
+ // A brief description of what the fuzzed code does.
+ Description string `json:"description,omitempty"`
+ // Can this code be triggered remotely or only locally.
+ Remotely_accessible *bool `json:"remotely_accessible,omitempty"`
+ // Is the fuzzed code host only, i.e. test frameworks or support utilities.
+ Host_only *bool `json:"host_only,omitempty"`
+ // Can third party/untrusted apps supply data to fuzzed code.
+ Untrusted_data *bool `json:"untrusted_data,omitempty"`
+ // Is the code being fuzzed in a privileged, constrained or any other
+ // context from:
+ // https://source.android.com/security/overview/updates-resources#context_types.
+ Privilege_level PrivilegedLevel `json:"privilege_level,omitempty"`
+ // Can the fuzzed code isolated or can be called by multiple users/processes.
+ Isolated *bool `json:"users_isolation,omitempty"`
+ // When code was relaeased or will be released.
+ Production_date string `json:"production_date,omitempty"`
+ // Prevents critical service functionality like phone calls, bluetooth, etc.
+ Critical *bool `json:"critical,omitempty"`
// Specify whether to enable continuous fuzzing on devices. Defaults to true.
Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"`
// Specify whether to enable continuous fuzzing on host. Defaults to true.
@@ -87,6 +153,12 @@
IsJni *bool `json:"is_jni,omitempty"`
}
+type FuzzFrameworks struct {
+ Afl *bool
+ Libfuzzer *bool
+ Jazzer *bool
+}
+
type FuzzProperties struct {
// Optional list of seed files to be installed to the fuzz target's output
// directory.
@@ -96,6 +168,10 @@
Data []string `android:"path"`
// Optional dictionary to be installed to the fuzz target's output directory.
Dictionary *string `android:"path"`
+ // Define the fuzzing frameworks this fuzz target can be built for. If
+ // empty then the fuzz target will be available to be built for all fuzz
+ // frameworks available
+ Fuzzing_frameworks *FuzzFrameworks
// Config for running the target on fuzzing infrastructure.
Fuzz_config *FuzzConfig
}
@@ -110,6 +186,49 @@
DataIntermediateDir android.Path
}
+func GetFramework(ctx android.LoadHookContext, lang Lang) Framework {
+ framework := ctx.Config().Getenv("FUZZ_FRAMEWORK")
+
+ if lang == Cc {
+ switch strings.ToLower(framework) {
+ case "":
+ return LibFuzzer
+ case "libfuzzer":
+ return LibFuzzer
+ case "afl":
+ return AFL
+ }
+ } else if lang == Rust {
+ return LibFuzzer
+ } else if lang == Java {
+ return Jazzer
+ }
+
+ ctx.ModuleErrorf(fmt.Sprintf("%s is not a valid fuzzing framework for %s", framework, lang))
+ return UnknownFramework
+}
+
+func IsValidFrameworkForModule(targetFramework Framework, lang Lang, moduleFrameworks *FuzzFrameworks) bool {
+ if targetFramework == UnknownFramework {
+ return false
+ }
+
+ if moduleFrameworks == nil {
+ return true
+ }
+
+ switch targetFramework {
+ case LibFuzzer:
+ return proptools.BoolDefault(moduleFrameworks.Libfuzzer, true)
+ case AFL:
+ return proptools.BoolDefault(moduleFrameworks.Afl, true)
+ case Jazzer:
+ return proptools.BoolDefault(moduleFrameworks.Jazzer, true)
+ default:
+ panic("%s is not supported as a fuzz framework")
+ }
+}
+
func IsValid(fuzzModule FuzzModule) bool {
// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
// fuzz targets we're going to package anyway.
@@ -157,7 +276,7 @@
}
// Additional fuzz config.
- if fuzzModule.Config != nil {
+ if fuzzModule.Config != nil && IsValidConfig(fuzzModule, module.Name()) {
files = append(files, FileToZip{fuzzModule.Config, ""})
}
@@ -208,7 +327,7 @@
return string(b)
}
-func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, lang Lang, pctx android.PackageContext) {
+func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, fuzzType Lang, pctx android.PackageContext) {
var archOsList []ArchOs
for archOs := range archDirs {
archOsList = append(archOsList, archOs)
@@ -221,12 +340,13 @@
hostOrTarget := archOs.HostOrTarget
builder := android.NewRuleBuilder(pctx, ctx)
zipFileName := "fuzz-" + hostOrTarget + "-" + arch + ".zip"
- if lang == Rust {
+ if fuzzType == Rust {
zipFileName = "fuzz-rust-" + hostOrTarget + "-" + arch + ".zip"
}
- if lang == Java {
+ if fuzzType == Java {
zipFileName = "fuzz-java-" + hostOrTarget + "-" + arch + ".zip"
}
+
outputFile := android.PathForOutput(ctx, zipFileName)
s.Packages = append(s.Packages, outputFile)
@@ -237,7 +357,6 @@
Flag("-L 0") // No need to try and re-compress the zipfiles.
for _, fileToZip := range filesToZip {
-
if fileToZip.DestinationPathPrefix != "" {
command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix)
} else {
@@ -256,6 +375,7 @@
for target, _ := range s.FuzzTargets {
fuzzTargets = append(fuzzTargets, target)
}
+
sort.Strings(fuzzTargets)
ctx.Strict(targets, strings.Join(fuzzTargets, " "))
}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 8649b15..b796877 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -266,7 +266,7 @@
var bazelOutputFiles android.Paths
exportIncludeDirs := map[string]bool{}
for _, bazelOutputFile := range filePaths {
- bazelOutputFiles = append(bazelOutputFiles, android.PathForBazelOut(ctx, bazelOutputFile))
+ bazelOutputFiles = append(bazelOutputFiles, android.PathForBazelOutRelative(ctx, ctx.ModuleDir(), bazelOutputFile))
exportIncludeDirs[filepath.Dir(bazelOutputFile)] = true
}
g.outputFiles = bazelOutputFiles
@@ -590,6 +590,18 @@
}
func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Allowlist genrule to use depfile until we have a solution to remove it.
+ // TODO(b/235582219): Remove allowlist for genrule
+ if ctx.ModuleType() == "gensrcs" &&
+ !ctx.DeviceConfig().BuildBrokenDepfile() &&
+ Bool(g.properties.Depfile) {
+ ctx.PropertyErrorf(
+ "depfile",
+ "Deprecated to ensure the module type is convertible to Bazel. "+
+ "Try specifying the dependencies explicitly so that there is no need to use depfile. "+
+ "If not possible, the escape hatch is to use BUILD_BROKEN_DEPFILE to bypass the error.")
+ }
+
g.generateCommonBuildActions(ctx)
// For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
@@ -805,6 +817,7 @@
func GenSrcsFactory() android.Module {
m := NewGenSrcs()
android.InitAndroidModule(m)
+ android.InitBazelModule(m)
return m
}
@@ -816,6 +829,13 @@
Shard_size *int64
}
+type bazelGensrcsAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Output_extension *string
+ Tools bazel.LabelListAttribute
+ Cmd string
+}
+
const defaultShardSize = 50
func NewGenRule() *Module {
@@ -880,8 +900,14 @@
// Replace in and out variables with $< and $@
var cmd string
if m.properties.Cmd != nil {
- cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
- cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
+ if ctx.ModuleType() == "gensrcs" {
+ cmd = strings.ReplaceAll(*m.properties.Cmd, "$(in)", "$(SRC)")
+ cmd = strings.ReplaceAll(cmd, "$(out)", "$(OUT)")
+ } else {
+ cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
+ cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
+ }
+
genDir := "$(GENDIR)"
if t := ctx.ModuleType(); t == "cc_genrule" || t == "java_genrule" || t == "java_genrule_host" {
genDir = "$(RULEDIR)"
@@ -901,30 +927,50 @@
}
}
- // The Out prop is not in an immediately accessible field
- // in the Module struct, so use GetProperties and cast it
- // to the known struct prop.
- var outs []string
- for _, propIntf := range m.GetProperties() {
- if props, ok := propIntf.(*genRuleProperties); ok {
- outs = props.Out
- break
+ if ctx.ModuleType() == "gensrcs" {
+ // The Output_extension prop is not in an immediately accessible field
+ // in the Module struct, so use GetProperties and cast it
+ // to the known struct prop.
+ var outputExtension *string
+ for _, propIntf := range m.GetProperties() {
+ if props, ok := propIntf.(*genSrcsProperties); ok {
+ outputExtension = props.Output_extension
+ break
+ }
}
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "gensrcs",
+ Bzl_load_location: "//build/bazel/rules:gensrcs.bzl",
+ }
+ attrs := &bazelGensrcsAttributes{
+ Srcs: srcs,
+ Output_extension: outputExtension,
+ Cmd: cmd,
+ Tools: tools,
+ }
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+ } else {
+ // The Out prop is not in an immediately accessible field
+ // in the Module struct, so use GetProperties and cast it
+ // to the known struct prop.
+ var outs []string
+ for _, propIntf := range m.GetProperties() {
+ if props, ok := propIntf.(*genRuleProperties); ok {
+ outs = props.Out
+ break
+ }
+ }
+ attrs := &bazelGenruleAttributes{
+ Srcs: srcs,
+ Outs: outs,
+ Cmd: cmd,
+ Tools: tools,
+ }
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "genrule",
+ }
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
}
-
- attrs := &bazelGenruleAttributes{
- Srcs: srcs,
- Outs: outs,
- Cmd: cmd,
- Tools: tools,
- }
-
- props := bazel.BazelTargetModuleProperties{
- Rule_class: "genrule",
- }
-
- // Create the BazelTargetModule.
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
}
var Bool = proptools.Bool
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 1b5cef2..b9be1f7 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -15,6 +15,7 @@
package genrule
import (
+ "fmt"
"os"
"regexp"
"testing"
@@ -626,6 +627,73 @@
}
}
+func TestGensrcsBuildBrokenDepfile(t *testing.T) {
+ tests := []struct {
+ name string
+ prop string
+ BuildBrokenDepfile *bool
+ err string
+ }{
+ {
+ name: `error when BuildBrokenDepfile is set to false`,
+ prop: `
+ depfile: true,
+ cmd: "cat $(in) > $(out) && cat $(depfile)",
+ `,
+ BuildBrokenDepfile: proptools.BoolPtr(false),
+ err: "depfile: Deprecated to ensure the module type is convertible to Bazel",
+ },
+ {
+ name: `error when BuildBrokenDepfile is not set`,
+ prop: `
+ depfile: true,
+ cmd: "cat $(in) > $(out) && cat $(depfile)",
+ `,
+ err: "depfile: Deprecated to ensure the module type is convertible to Bazel.",
+ },
+ {
+ name: `no error when BuildBrokenDepfile is explicitly set to true`,
+ prop: `
+ depfile: true,
+ cmd: "cat $(in) > $(out) && cat $(depfile)",
+ `,
+ BuildBrokenDepfile: proptools.BoolPtr(true),
+ },
+ {
+ name: `no error if depfile is not set`,
+ prop: `
+ cmd: "cat $(in) > $(out)",
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ bp := fmt.Sprintf(`
+ gensrcs {
+ name: "foo",
+ srcs: ["data.txt"],
+ %s
+ }`, test.prop)
+
+ var expectedErrors []string
+ if test.err != "" {
+ expectedErrors = append(expectedErrors, test.err)
+ }
+ android.GroupFixturePreparers(
+ prepareForGenRuleTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ if test.BuildBrokenDepfile != nil {
+ variables.BuildBrokenDepfile = test.BuildBrokenDepfile
+ }
+ }),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
+ RunTestWithBp(t, bp)
+ })
+
+ }
+}
+
func TestGenruleDefaults(t *testing.T) {
bp := `
genrule_defaults {
diff --git a/go.mod b/go.mod
index 14444b3..8c1a9f0 100644
--- a/go.mod
+++ b/go.mod
@@ -16,4 +16,4 @@
// Indirect dep from go-cmp
exclude golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
-go 1.15
+go 1.18
diff --git a/java/Android.bp b/java/Android.bp
index df0d1eb..9df4ab4 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -76,6 +76,7 @@
"tradefed.go",
],
testSrcs: [
+ "aar_test.go",
"androidmk_test.go",
"app_import_test.go",
"app_set_test.go",
@@ -87,6 +88,7 @@
"dexpreopt_bootjars_test.go",
"droiddoc_test.go",
"droidstubs_test.go",
+ "genrule_test.go",
"hiddenapi_singleton_test.go",
"jacoco_test.go",
"java_test.go",
@@ -97,6 +99,7 @@
"platform_compat_config_test.go",
"plugin_test.go",
"prebuilt_apis_test.go",
+ "proto_test.go",
"rro_test.go",
"sdk_test.go",
"sdk_library_test.go",
diff --git a/java/aar.go b/java/aar.go
index 00ff7e7..d5996ba 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -21,6 +21,7 @@
"strings"
"android/soong/android"
+ "android/soong/bazel"
"android/soong/dexpreopt"
"github.com/google/blueprint"
@@ -105,6 +106,7 @@
noticeFile android.OptionalPath
assetPackage android.OptionalPath
isLibrary bool
+ defaultManifestVersion string
useEmbeddedNativeLibs bool
useEmbeddedDex bool
usesNonSdkApis bool
@@ -281,14 +283,15 @@
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{
- SdkContext: sdkContext,
- ClassLoaderContexts: classLoaderContexts,
- IsLibrary: a.isLibrary,
- UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs,
- UsesNonSdkApis: a.usesNonSdkApis,
- UseEmbeddedDex: a.useEmbeddedDex,
- HasNoCode: a.hasNoCode,
- LoggingParent: a.LoggingParent,
+ SdkContext: sdkContext,
+ ClassLoaderContexts: classLoaderContexts,
+ IsLibrary: a.isLibrary,
+ DefaultManifestVersion: a.defaultManifestVersion,
+ UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs,
+ UsesNonSdkApis: a.usesNonSdkApis,
+ UseEmbeddedDex: a.useEmbeddedDex,
+ HasNoCode: a.hasNoCode,
+ LoggingParent: a.LoggingParent,
})
// Add additional manifest files to transitive manifests.
@@ -488,6 +491,7 @@
type AndroidLibrary struct {
Library
aapt
+ android.BazelModuleBase
androidLibraryProperties androidLibraryProperties
@@ -570,12 +574,24 @@
a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles)
a.exportedStaticPackages = android.FirstUniquePaths(a.exportedStaticPackages)
+
+ prebuiltJniPackages := android.Paths{}
+ ctx.VisitDirectDeps(func(module android.Module) {
+ if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok {
+ prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...)
+ }
+ })
+ if len(prebuiltJniPackages) > 0 {
+ ctx.SetProvider(JniPackageProvider, JniPackageInfo{
+ JniPackages: prebuiltJniPackages,
+ })
+ }
}
// android_library builds and links sources into a `.jar` file for the device along with Android resources.
//
// An android_library has a single variant that produces a `.jar` file containing `.class` files that were
-// compiled against the device bootclasspath, along with a `package-res.apk` file containing Android resources compiled
+// compiled against the device bootclasspath, along with a `package-res.apk` file containing Android resources compiled
// with aapt2. This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of
// an android_app module.
func AndroidLibraryFactory() android.Module {
@@ -591,6 +607,7 @@
android.InitApexModule(module)
InitJavaModule(module, android.DeviceSupported)
+ android.InitBazelModule(module)
return module
}
@@ -619,12 +636,17 @@
Libs []string
// If set to true, run Jetifier against .aar file. Defaults to false.
Jetifier *bool
+ // If true, extract JNI libs from AAR archive. These libs will be accessible to android_app modules and
+ // will be passed transitively through android_libraries to an android_app.
+ //TODO(b/241138093) evaluate whether we can have this flag default to true for Bazel conversion
+ Extract_jni *bool
}
type AARImport struct {
android.ModuleBase
android.DefaultableModuleBase
android.ApexModuleBase
+ android.BazelModuleBase
prebuilt android.Prebuilt
// Functionality common to Module and Import.
@@ -643,7 +665,8 @@
hideApexVariantFromMake bool
- aarPath android.Path
+ aarPath android.Path
+ jniPackages android.Paths
sdkVersion android.SdkSpec
minSdkVersion android.SdkSpec
@@ -678,6 +701,10 @@
return a.SdkVersion(ctx)
}
+func (a *AARImport) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, "")
+}
+
func (a *AARImport) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
return a.SdkVersion(ctx)
}
@@ -747,6 +774,28 @@
ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs...)
}
+type JniPackageInfo struct {
+ // List of zip files containing JNI libraries
+ // Zip files should have directory structure jni/<arch>/*.so
+ JniPackages android.Paths
+}
+
+var JniPackageProvider = blueprint.NewProvider(JniPackageInfo{})
+
+// Unzip an AAR and extract the JNI libs for $archString.
+var extractJNI = pctx.AndroidStaticRule("extractJNI",
+ blueprint.RuleParams{
+ Command: `rm -rf $out $outDir && touch $out && ` +
+ `unzip -qoDD -d $outDir $in "jni/${archString}/*" && ` +
+ `jni_files=$$(find $outDir/jni -type f) && ` +
+ // print error message if there are no JNI libs for this arch
+ `[ -n "$$jni_files" ] || (echo "ERROR: no JNI libs found for arch ${archString}" && exit 1) && ` +
+ `${config.SoongZipCmd} -o $out -P 'lib/${archString}' ` +
+ `-C $outDir/jni/${archString} $$(echo $$jni_files | xargs -n1 printf " -f %s")`,
+ CommandDeps: []string{"${config.SoongZipCmd}"},
+ },
+ "outDir", "archString")
+
// Unzip an AAR into its constituent files and directories. Any files in Outputs that don't exist in the AAR will be
// touched to create an empty file. The res directory is not extracted, as it will be extracted in its own rule.
var unzipAAR = pctx.AndroidStaticRule("unzipAAR",
@@ -854,6 +903,31 @@
ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
ImplementationJars: android.PathsIfNonNil(a.classpathFile),
})
+
+ if proptools.Bool(a.properties.Extract_jni) {
+ for _, t := range ctx.MultiTargets() {
+ arch := t.Arch.Abi[0]
+ path := android.PathForModuleOut(ctx, arch+"_jni.zip")
+ a.jniPackages = append(a.jniPackages, path)
+
+ outDir := android.PathForModuleOut(ctx, "aarForJni")
+ aarPath := android.PathForModuleSrc(ctx, a.properties.Aars[0])
+ ctx.Build(pctx, android.BuildParams{
+ Rule: extractJNI,
+ Input: aarPath,
+ Outputs: android.WritablePaths{path},
+ Description: "extract JNI from AAR",
+ Args: map[string]string{
+ "outDir": outDir.String(),
+ "archString": arch,
+ },
+ })
+ }
+
+ ctx.SetProvider(JniPackageProvider, JniPackageInfo{
+ JniPackages: a.jniPackages,
+ })
+ }
}
func (a *AARImport) HeaderJars() android.Paths {
@@ -889,7 +963,7 @@
return nil
}
-var _ android.PrebuiltInterface = (*Import)(nil)
+var _ android.PrebuiltInterface = (*AARImport)(nil)
// android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
//
@@ -902,6 +976,97 @@
android.InitPrebuiltModule(module, &module.properties.Aars)
android.InitApexModule(module)
- InitJavaModule(module, android.DeviceSupported)
+ InitJavaModuleMultiTargets(module, android.DeviceSupported)
+ android.InitBazelModule(module)
return module
}
+
+type bazelAapt struct {
+ Manifest bazel.Label
+ Resource_files bazel.LabelListAttribute
+}
+
+type bazelAndroidLibrary struct {
+ *javaLibraryAttributes
+ *bazelAapt
+}
+
+type bazelAndroidLibraryImport struct {
+ Aar bazel.Label
+ Deps bazel.LabelListAttribute
+ Exports bazel.LabelListAttribute
+}
+
+func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) *bazelAapt {
+ manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
+
+ resourceFiles := bazel.LabelList{
+ Includes: []bazel.Label{},
+ }
+ for _, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") {
+ files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir))
+ resourceFiles.Includes = append(resourceFiles.Includes, files...)
+ }
+ return &bazelAapt{
+ android.BazelLabelForModuleSrcSingle(ctx, manifest),
+ bazel.MakeLabelListAttribute(resourceFiles),
+ }
+}
+
+func (a *AARImport) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ aars := android.BazelLabelForModuleSrcExcludes(ctx, a.properties.Aars, []string{})
+ exportableStaticLibs := []string{}
+ // TODO(b/240716882): investigate and handle static_libs deps that are not imports. They are not supported for export by Bazel.
+ for _, depName := range a.properties.Static_libs {
+ if dep, ok := ctx.ModuleFromName(depName); ok {
+ switch dep.(type) {
+ case *AARImport, *Import:
+ exportableStaticLibs = append(exportableStaticLibs, depName)
+ }
+ }
+ }
+ name := android.RemoveOptionalPrebuiltPrefix(a.Name())
+ deps := android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(append(a.properties.Static_libs, a.properties.Libs...))))
+ exports := android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(exportableStaticLibs))
+
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "aar_import",
+ Bzl_load_location: "@rules_android//rules:rules.bzl",
+ },
+ android.CommonAttributes{Name: name},
+ &bazelAndroidLibraryImport{
+ Aar: aars.Includes[0],
+ Deps: bazel.MakeLabelListAttribute(deps),
+ Exports: bazel.MakeLabelListAttribute(exports),
+ },
+ )
+
+}
+
+func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ commonAttrs, depLabels := a.convertLibraryAttrsBp2Build(ctx)
+
+ deps := depLabels.Deps
+ if !commonAttrs.Srcs.IsEmpty() {
+ deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them
+ } else if !depLabels.Deps.IsEmpty() {
+ ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.")
+ }
+
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "android_library",
+ Bzl_load_location: "@rules_android//rules:rules.bzl",
+ },
+ android.CommonAttributes{Name: a.Name()},
+ &bazelAndroidLibrary{
+ &javaLibraryAttributes{
+ javaCommonAttributes: commonAttrs,
+ Deps: deps,
+ Exports: depLabels.StaticDeps,
+ },
+ a.convertAaptAttrsWithBp2Build(ctx),
+ },
+ )
+}
diff --git a/java/aar_test.go b/java/aar_test.go
new file mode 100644
index 0000000..8afa039
--- /dev/null
+++ b/java/aar_test.go
@@ -0,0 +1,83 @@
+// 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 java
+
+import (
+ "android/soong/android"
+ "testing"
+)
+
+func TestAarImportProducesJniPackages(t *testing.T) {
+ ctx := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ ).RunTestWithBp(t, `
+ android_library_import {
+ name: "aar-no-jni",
+ aars: ["aary.aar"],
+ }
+ android_library_import {
+ name: "aar-jni",
+ aars: ["aary.aar"],
+ extract_jni: true,
+ }`)
+
+ testCases := []struct {
+ name string
+ hasPackage bool
+ }{
+ {
+ name: "aar-no-jni",
+ hasPackage: false,
+ },
+ {
+ name: "aar-jni",
+ hasPackage: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ appMod := ctx.Module(tc.name, "android_common")
+ appTestMod := ctx.ModuleForTests(tc.name, "android_common")
+
+ info, ok := ctx.ModuleProvider(appMod, JniPackageProvider).(JniPackageInfo)
+ if !ok {
+ t.Errorf("expected android_library_import to have JniPackageProvider")
+ }
+
+ if !tc.hasPackage {
+ if len(info.JniPackages) != 0 {
+ t.Errorf("expected JniPackages to be empty, but got %v", info.JniPackages)
+ }
+ outputFile := "arm64-v8a_jni.zip"
+ jniOutputLibZip := appTestMod.MaybeOutput(outputFile)
+ if jniOutputLibZip.Rule != nil {
+ t.Errorf("did not expect an output file, but found %v", outputFile)
+ }
+ return
+ }
+
+ if len(info.JniPackages) != 1 {
+ t.Errorf("expected a single JniPackage, but got %v", info.JniPackages)
+ }
+
+ outputFile := info.JniPackages[0].String()
+ jniOutputLibZip := appTestMod.Output(outputFile)
+ if jniOutputLibZip.Rule == nil {
+ t.Errorf("did not find output file %v", outputFile)
+ }
+ })
+ }
+}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index a297b2c..522b664 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -45,7 +45,11 @@
// This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK
func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext android.SdkContext) string {
targetSdkVersionSpec := sdkContext.TargetSdkVersion(ctx)
- if ctx.Config().UnbundledBuildApps() && targetSdkVersionSpec.ApiLevel.IsPreview() {
+ // Return 10000 for modules targeting "current" if either
+ // 1. The module is built in unbundled mode (TARGET_BUILD_APPS not empty)
+ // 2. The module is run as part of MTS, and should be testable on stable branches
+ // TODO(b/240294501): Determine the rules for handling test apexes
+ if targetSdkVersionSpec.ApiLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module())) {
return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt())
}
targetSdkVersion, err := targetSdkVersionSpec.EffectiveVersionString(ctx)
@@ -55,16 +59,26 @@
return targetSdkVersion
}
+// Helper function that casts android.Module to java.androidTestApp
+// If this type conversion is possible, it queries whether the test app is included in an MTS suite
+func includedInMts(module android.Module) bool {
+ if test, ok := module.(androidTestApp); ok {
+ return test.includedInTestSuite("mts")
+ }
+ return false
+}
+
type ManifestFixerParams struct {
- SdkContext android.SdkContext
- ClassLoaderContexts dexpreopt.ClassLoaderContextMap
- IsLibrary bool
- UseEmbeddedNativeLibs bool
- UsesNonSdkApis bool
- UseEmbeddedDex bool
- HasNoCode bool
- TestOnly bool
- LoggingParent string
+ SdkContext android.SdkContext
+ ClassLoaderContexts dexpreopt.ClassLoaderContextMap
+ IsLibrary bool
+ DefaultManifestVersion string
+ UseEmbeddedNativeLibs bool
+ UsesNonSdkApis bool
+ UseEmbeddedDex bool
+ HasNoCode bool
+ TestOnly bool
+ LoggingParent string
}
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
@@ -136,6 +150,11 @@
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
+ replaceMaxSdkVersionPlaceholder, err := params.SdkContext.ReplaceMaxSdkVersionPlaceholder(ctx).EffectiveVersion(ctx)
+ if err != nil {
+ ctx.ModuleErrorf("invalid ReplaceMaxSdkVersionPlaceholder: %s", err)
+ }
+
if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
deps = append(deps, ApiFingerprintPath(ctx))
@@ -145,8 +164,12 @@
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
args = append(args, "--minSdkVersion ", minSdkVersion)
+ args = append(args, "--replaceMaxSdkVersionPlaceholder ", strconv.Itoa(replaceMaxSdkVersionPlaceholder.FinalOrFutureInt()))
args = append(args, "--raise-min-sdk-version")
}
+ if params.DefaultManifestVersion != "" {
+ args = append(args, "--override-placeholder-version", params.DefaultManifestVersion)
+ }
fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
argsMapper["args"] = strings.Join(args, " ")
diff --git a/java/androidmk.go b/java/androidmk.go
index 330e594..4cf5ee4 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -419,7 +419,15 @@
entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports)
},
},
- }}
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string) {
+ if app.javaApiUsedByOutputFile.String() != "" {
+ fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s/$(notdir %s))\n",
+ app.installApkName, app.javaApiUsedByOutputFile.String(), "java_apis_used_by_apex", app.javaApiUsedByOutputFile.String())
+ }
+ },
+ }},
+ }
}
func (a *AndroidApp) getOverriddenPackages() []string {
@@ -623,6 +631,7 @@
if dstubs.apiLintReport != nil {
fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", dstubs.Name()+"-api-lint",
dstubs.apiLintReport.String(), "apilint/"+dstubs.Name()+"-lint-report.txt")
+ fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", dstubs.apiLintReport.String())
}
}
if dstubs.checkNullabilityWarningsTimestamp != nil {
diff --git a/java/app.go b/java/app.go
index 86238d5..bccd37f 100755
--- a/java/app.go
+++ b/java/app.go
@@ -117,6 +117,9 @@
// Name of the signing certificate lineage file or filegroup module.
Lineage *string `android:"path"`
+ // For overriding the --rotation-min-sdk-version property of apksig
+ RotationMinSdkVersion *string
+
// the package name of this app. The package name in the manifest file is used if one was not given.
Package_name *string
@@ -165,6 +168,8 @@
overriddenManifestPackageName string
android.ApexBundleDepsInfo
+
+ javaApiUsedByOutputFile android.ModuleOutPath
}
func (a *AndroidApp) IsInstallable() bool {
@@ -273,6 +278,7 @@
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.checkAppSdkVersions(ctx)
a.generateAndroidBuildActions(ctx)
+ a.generateJavaUsedByApex(ctx)
}
func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
@@ -417,6 +423,9 @@
a.aapt.splitNames = a.appProperties.Package_splits
a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent)
+ if a.Updatable() {
+ a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion
+ }
a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts,
a.usesLibraryProperties.Exclude_uses_libs, aaptLinkFlags...)
@@ -472,14 +481,14 @@
return a.dexJarFile.PathOrNil()
}
-func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
+func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages android.Paths, ctx android.ModuleContext) android.WritablePath {
var jniJarFile android.WritablePath
- if len(jniLibs) > 0 {
+ if len(jniLibs) > 0 || len(prebuiltJniPackages) > 0 {
a.jniLibs = jniLibs
if a.shouldEmbedJnis(ctx) {
jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
a.installPathForJNISymbols = a.installPath(ctx)
- TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
+ TransformJniLibsToJar(ctx, jniJarFile, jniLibs, prebuiltJniPackages, a.useEmbeddedNativeLibs(ctx))
for _, jni := range jniLibs {
if jni.coverageFile.Valid() {
// Only collect coverage for the first target arch if this is a multilib target.
@@ -583,6 +592,16 @@
a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+ var noticeAssetPath android.WritablePath
+ if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
+ // The rule to create the notice file can't be generated yet, as the final output path
+ // for the apk isn't known yet. Add the path where the notice file will be generated to the
+ // aapt rules now before calling aaptBuildActions, the rule to create the notice file will
+ // be generated later.
+ noticeAssetPath = android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
+ a.aapt.noticeFile = android.OptionalPathForPath(noticeAssetPath)
+ }
+
// Process all building blocks, from AAPT to certificates.
a.aaptBuildActions(ctx)
@@ -613,8 +632,8 @@
dexJarFile := a.dexBuildActions(ctx)
- jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
- jniJarFile := a.jniBuildActions(jniLibs, ctx)
+ jniLibs, prebuiltJniPackages, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
+ jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx)
if ctx.Failed() {
return
@@ -648,22 +667,30 @@
if lineage := String(a.overridableAppProperties.Lineage); lineage != "" {
lineageFile = android.PathForModuleSrc(ctx, lineage)
}
- CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile)
+
+ rotationMinSdkVersion := String(a.overridableAppProperties.RotationMinSdkVersion)
+
+ CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
a.outputFile = packageFile
if v4SigningRequested {
a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
}
- if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
+ if a.aapt.noticeFile.Valid() {
+ // Generating the notice file rule has to be here after a.outputFile is known.
noticeFile := android.PathForModuleOut(ctx, "NOTICE.html.gz")
- android.BuildNoticeHtmlOutputFromLicenseMetadata(ctx, noticeFile, "", "", a.outputFile.String())
- noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
+ android.BuildNoticeHtmlOutputFromLicenseMetadata(
+ ctx, noticeFile, "", "",
+ []string{
+ a.installDir.String() + "/",
+ android.PathForModuleInstall(ctx).String() + "/",
+ a.outputFile.String(),
+ })
builder := android.NewRuleBuilder(pctx, ctx)
builder.Command().Text("cp").
Input(noticeFile).
Output(noticeAssetPath)
builder.Build("notice_dir", "Building notice dir")
- a.aapt.noticeFile = android.OptionalPathForPath(noticeAssetPath)
}
for _, split := range a.aapt.splits {
@@ -672,7 +699,7 @@
if v4SigningRequested {
v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig")
}
- CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile)
+ CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
if v4SigningRequested {
a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
@@ -709,9 +736,10 @@
func collectAppDeps(ctx android.ModuleContext, app appDepsInterface,
shouldCollectRecursiveNativeDeps bool,
- checkNativeSdkVersion bool) ([]jniLib, []Certificate) {
+ checkNativeSdkVersion bool) ([]jniLib, android.Paths, []Certificate) {
var jniLibs []jniLib
+ var prebuiltJniPackages android.Paths
var certificates []Certificate
seenModulePaths := make(map[string]bool)
@@ -725,7 +753,7 @@
tag := ctx.OtherModuleDependencyTag(module)
if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) {
- if dep, ok := module.(*cc.Module); ok {
+ if dep, ok := module.(cc.LinkableInterface); ok {
if dep.IsNdk(ctx.Config()) || dep.IsStubs() {
return false
}
@@ -760,6 +788,10 @@
return shouldCollectRecursiveNativeDeps
}
+ if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok {
+ prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...)
+ }
+
if tag == certificateTag {
if dep, ok := module.(*AndroidAppCertificate); ok {
certificates = append(certificates, dep.Certificate)
@@ -771,7 +803,7 @@
return false
})
- return jniLibs, certificates
+ return jniLibs, prebuiltJniPackages, certificates
}
func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
@@ -939,6 +971,18 @@
return true
}
+type androidTestApp interface {
+ includedInTestSuite(searchPrefix string) bool
+}
+
+func (a *AndroidTest) includedInTestSuite(searchPrefix string) bool {
+ return android.PrefixInList(a.testProperties.Test_suites, searchPrefix)
+}
+
+func (a *AndroidTestHelperApp) includedInTestSuite(searchPrefix string) bool {
+ return android.PrefixInList(a.appTestHelperAppProperties.Test_suites, searchPrefix)
+}
+
func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var configs []tradefed.Config
if a.appTestProperties.Instrumentation_target_package != nil {
@@ -1012,7 +1056,7 @@
func AndroidTestFactory() android.Module {
module := &AndroidTest{}
- module.Module.dexProperties.Optimize.EnabledByDefault = true
+ module.Module.dexProperties.Optimize.EnabledByDefault = false
module.Module.properties.Instrument = true
module.Module.properties.Supports_static_instrumentation = true
@@ -1020,7 +1064,7 @@
module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.appProperties.AlwaysPackageNativeLibs = true
module.Module.dexpreopter.isTest = true
- module.Module.linter.test = true
+ module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
module.addHostAndDeviceProperties()
module.AddProperties(
@@ -1066,13 +1110,14 @@
func AndroidTestHelperAppFactory() android.Module {
module := &AndroidTestHelperApp{}
+ // TODO(b/192032291): Disable by default after auditing downstream usage.
module.Module.dexProperties.Optimize.EnabledByDefault = true
module.Module.properties.Installable = proptools.BoolPtr(true)
module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.appProperties.AlwaysPackageNativeLibs = true
module.Module.dexpreopter.isTest = true
- module.Module.linter.test = true
+ module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
module.addHostAndDeviceProperties()
module.AddProperties(
@@ -1341,7 +1386,7 @@
Flag("--enforce-uses-libraries").
Input(inputFile).
FlagWithOutput("--enforce-uses-libraries-status ", statusFile).
- FlagWithInput("--aapt ", ctx.Config().HostToolPath(ctx, "aapt"))
+ FlagWithInput("--aapt ", ctx.Config().HostToolPath(ctx, "aapt2"))
if outputFile != nil {
cmd.FlagWithOutput("-o ", outputFile)
@@ -1408,10 +1453,9 @@
type bazelAndroidAppAttributes struct {
*javaCommonAttributes
+ *bazelAapt
Deps bazel.LabelListAttribute
- Manifest bazel.Label
Custom_package *string
- Resource_files bazel.LabelListAttribute
Certificate *bazel.Label
Certificate_name *string
}
@@ -1421,23 +1465,9 @@
commonAttrs, depLabels := a.convertLibraryAttrsBp2Build(ctx)
deps := depLabels.Deps
- if !commonAttrs.Srcs.IsEmpty() {
- deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them
- } else if !deps.IsEmpty() || !depLabels.StaticDeps.IsEmpty() {
- ctx.ModuleErrorf("android_app has dynamic or static dependencies but no sources." +
- " Bazel does not allow direct dependencies without sources nor exported" +
- " dependencies on android_binary rule.")
- }
+ deps.Append(depLabels.StaticDeps)
- manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
-
- resourceFiles := bazel.LabelList{
- Includes: []bazel.Label{},
- }
- for _, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") {
- files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir))
- resourceFiles.Includes = append(resourceFiles.Includes, files...)
- }
+ aapt := a.convertAaptAttrsWithBp2Build(ctx)
var certificate *bazel.Label
certificateNamePtr := a.overridableAppProperties.Certificate
@@ -1448,14 +1478,12 @@
certificate = &c
certificateNamePtr = nil
}
-
attrs := &bazelAndroidAppAttributes{
commonAttrs,
+ aapt,
deps,
- android.BazelLabelForModuleSrcSingle(ctx, manifest),
// TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
a.overridableAppProperties.Package_name,
- bazel.MakeLabelListAttribute(resourceFiles),
certificate,
certificateNamePtr,
}
@@ -1464,7 +1492,6 @@
Rule_class: "android_binary",
Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
}
-
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, attrs)
}
diff --git a/java/app_builder.go b/java/app_builder.go
index 4a18dca..18a9751 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -52,7 +52,7 @@
})
func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
- packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path) {
+ packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) {
unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -73,10 +73,10 @@
Implicits: deps,
})
- SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile)
+ SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile, rotationMinSdkVersion)
}
-func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath, lineageFile android.Path) {
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) {
var certificateArgs []string
var deps android.Paths
@@ -97,6 +97,10 @@
deps = append(deps, lineageFile)
}
+ if rotationMinSdkVersion != "" {
+ flags = append(flags, "--rotation-min-sdk-version", rotationMinSdkVersion)
+ }
+
rule := Signapk
args := map[string]string{
"certificates": strings.Join(certificateArgs, " "),
@@ -218,8 +222,14 @@
})
}
-func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.WritablePath,
- jniLibs []jniLib, uncompressJNI bool) {
+const jniJarOutputPathString = "jniJarOutput.zip"
+
+func TransformJniLibsToJar(
+ ctx android.ModuleContext,
+ outputFile android.WritablePath,
+ jniLibs []jniLib,
+ prebuiltJniPackages android.Paths,
+ uncompressJNI bool) {
var deps android.Paths
jarArgs := []string{
@@ -245,13 +255,32 @@
rule = zipRE
args["implicits"] = strings.Join(deps.Strings(), ",")
}
+ jniJarPath := android.PathForModuleOut(ctx, jniJarOutputPathString)
ctx.Build(pctx, android.BuildParams{
Rule: rule,
Description: "zip jni libs",
- Output: outputFile,
+ Output: jniJarPath,
Implicits: deps,
Args: args,
})
+ ctx.Build(pctx, android.BuildParams{
+ Rule: mergeAssetsRule,
+ Description: "merge prebuilt JNI packages",
+ Inputs: append(prebuiltJniPackages, jniJarPath),
+ Output: outputFile,
+ })
+}
+
+func (a *AndroidApp) generateJavaUsedByApex(ctx android.ModuleContext) {
+ javaApiUsedByOutputFile := android.PathForModuleOut(ctx, a.installApkName+"_using.xml")
+ javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
+ javaUsedByRule.Command().
+ Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
+ BuiltTool("dexdeps").
+ Output(javaApiUsedByOutputFile).
+ Input(a.Library.Module.outputFile)
+ javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
+ a.javaApiUsedByOutputFile = javaApiUsedByOutputFile
}
func targetToJniDir(target android.Target) string {
diff --git a/java/app_import.go b/java/app_import.go
index b017eca..4bab14b 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -80,6 +80,9 @@
// Name of the signing certificate lineage file or filegroup module.
Lineage *string `android:"path"`
+ // For overriding the --rotation-min-sdk-version property of apksig
+ RotationMinSdkVersion *string
+
// Sign with the default system dev certificate. Must be used judiciously. Most imported apps
// need to either specify a specific certificate or be presigned.
Default_dev_cert *bool
@@ -256,7 +259,7 @@
ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
}
- _, certificates := collectAppDeps(ctx, a, false, false)
+ _, _, certificates := collectAppDeps(ctx, a, false, false)
// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
// TODO: LOCAL_PACKAGE_SPLITS
@@ -333,7 +336,10 @@
if lineage := String(a.properties.Lineage); lineage != "" {
lineageFile = android.PathForModuleSrc(ctx, lineage)
}
- SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile)
+
+ rotationMinSdkVersion := String(a.properties.RotationMinSdkVersion)
+
+ SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile, rotationMinSdkVersion)
a.outputFile = signed
} else {
alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 8f6c75f..41be092 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -129,6 +129,7 @@
certificate: "platform",
additional_certificates: [":additional_certificate"],
lineage: "lineage.bin",
+ rotationMinSdkVersion: "32",
}
android_app_certificate {
@@ -148,11 +149,12 @@
if expected != certificatesFlag {
t.Errorf("Incorrect certificates flags, expected: %q, got: %q", expected, certificatesFlag)
}
- // Check cert signing lineage flag.
- signingFlag := signedApk.Args["flags"]
- expected = "--lineage lineage.bin"
- if expected != signingFlag {
- t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+
+ // Check cert signing flags.
+ actualCertSigningFlags := signedApk.Args["flags"]
+ expectedCertSigningFlags := "--lineage lineage.bin --rotation-min-sdk-version 32"
+ if expectedCertSigningFlags != actualCertSigningFlags {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", expectedCertSigningFlags, actualCertSigningFlags)
}
rule := variant.Rule("genProvenanceMetaData")
diff --git a/java/app_test.go b/java/app_test.go
index c4ac4df..23635b9 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1218,7 +1218,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
app := ctx.ModuleForTests(test.name, "android_common")
- jniLibZip := app.Output("jnilibs.zip")
+ jniLibZip := app.Output(jniJarOutputPathString)
var abis []string
args := strings.Fields(jniLibZip.Args["jarArgs"])
for i := 0; i < len(args); i++ {
@@ -1351,7 +1351,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
app := ctx.ModuleForTests(test.name, "android_common")
- jniLibZip := app.MaybeOutput("jnilibs.zip")
+ jniLibZip := app.MaybeOutput(jniJarOutputPathString)
if g, w := (jniLibZip.Rule != nil), test.packaged; g != w {
t.Errorf("expected jni packaged %v, got %v", w, g)
}
@@ -1442,7 +1442,7 @@
t.Run(test.name, func(t *testing.T) {
app := ctx.ModuleForTests(test.name, "android_common")
- jniLibZip := app.MaybeOutput("jnilibs.zip")
+ jniLibZip := app.MaybeOutput(jniJarOutputPathString)
if len(jniLibZip.Implicits) != 1 {
t.Fatalf("expected exactly one jni library, got %q", jniLibZip.Implicits.Strings())
}
@@ -1488,11 +1488,11 @@
func TestCertificates(t *testing.T) {
testCases := []struct {
- name string
- bp string
- certificateOverride string
- expectedLineage string
- expectedCertificate string
+ name string
+ bp string
+ certificateOverride string
+ expectedCertSigningFlags string
+ expectedCertificate string
}{
{
name: "default",
@@ -1503,9 +1503,9 @@
sdk_version: "current",
}
`,
- certificateOverride: "",
- expectedLineage: "",
- expectedCertificate: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
+ certificateOverride: "",
+ expectedCertSigningFlags: "",
+ expectedCertificate: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
},
{
name: "module certificate property",
@@ -1522,9 +1522,9 @@
certificate: "cert/new_cert",
}
`,
- certificateOverride: "",
- expectedLineage: "",
- expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certificateOverride: "",
+ expectedCertSigningFlags: "",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
},
{
name: "path certificate property",
@@ -1536,9 +1536,9 @@
sdk_version: "current",
}
`,
- certificateOverride: "",
- expectedLineage: "",
- expectedCertificate: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certificateOverride: "",
+ expectedCertSigningFlags: "",
+ expectedCertificate: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
},
{
name: "certificate overrides",
@@ -1555,18 +1555,19 @@
certificate: "cert/new_cert",
}
`,
- certificateOverride: "foo:new_certificate",
- expectedLineage: "",
- expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certificateOverride: "foo:new_certificate",
+ expectedCertSigningFlags: "",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
},
{
- name: "certificate lineage",
+ name: "certificate signing flags",
bp: `
android_app {
name: "foo",
srcs: ["a.java"],
certificate: ":new_certificate",
lineage: "lineage.bin",
+ rotationMinSdkVersion: "32",
sdk_version: "current",
}
@@ -1575,18 +1576,19 @@
certificate: "cert/new_cert",
}
`,
- certificateOverride: "",
- expectedLineage: "--lineage lineage.bin",
- expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certificateOverride: "",
+ expectedCertSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
},
{
- name: "lineage from filegroup",
+ name: "cert signing flags from filegroup",
bp: `
android_app {
name: "foo",
srcs: ["a.java"],
certificate: ":new_certificate",
lineage: ":lineage_bin",
+ rotationMinSdkVersion: "32",
sdk_version: "current",
}
@@ -1600,9 +1602,9 @@
srcs: ["lineage.bin"],
}
`,
- certificateOverride: "",
- expectedLineage: "--lineage lineage.bin",
- expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certificateOverride: "",
+ expectedCertSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32",
+ expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
},
}
@@ -1623,8 +1625,8 @@
signCertificateFlags := signapk.Args["certificates"]
android.AssertStringEquals(t, "certificates flags", test.expectedCertificate, signCertificateFlags)
- signFlags := signapk.Args["flags"]
- android.AssertStringEquals(t, "signing flags", test.expectedLineage, signFlags)
+ certSigningFlags := signapk.Args["flags"]
+ android.AssertStringEquals(t, "cert signing flags", test.expectedCertSigningFlags, certSigningFlags)
})
}
}
@@ -1819,6 +1821,7 @@
base: "foo",
certificate: ":new_certificate",
lineage: "lineage.bin",
+ rotationMinSdkVersion: "32",
logging_parent: "bah",
}
@@ -1864,89 +1867,89 @@
`)
expectedVariants := []struct {
- name string
- moduleName string
- variantName string
- apkName string
- apkPath string
- certFlag string
- lineageFlag string
- overrides []string
- packageFlag string
- renameResources bool
- logging_parent string
+ name string
+ moduleName string
+ variantName string
+ apkName string
+ apkPath string
+ certFlag string
+ certSigningFlags string
+ overrides []string
+ packageFlag string
+ renameResources bool
+ logging_parent string
}{
{
- name: "foo",
- moduleName: "foo",
- variantName: "android_common",
- apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux"},
- packageFlag: "",
- renameResources: false,
- logging_parent: "",
+ name: "foo",
+ moduleName: "foo",
+ variantName: "android_common",
+ apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certSigningFlags: "",
+ overrides: []string{"qux"},
+ packageFlag: "",
+ renameResources: false,
+ logging_parent: "",
},
{
- name: "foo",
- moduleName: "bar",
- variantName: "android_common_bar",
- apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk",
- certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
- lineageFlag: "--lineage lineage.bin",
- overrides: []string{"qux", "foo"},
- packageFlag: "",
- renameResources: false,
- logging_parent: "bah",
+ name: "foo",
+ moduleName: "bar",
+ variantName: "android_common_bar",
+ apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk",
+ certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ certSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32",
+ overrides: []string{"qux", "foo"},
+ packageFlag: "",
+ renameResources: false,
+ logging_parent: "bah",
},
{
- name: "foo",
- moduleName: "baz",
- variantName: "android_common_baz",
- apkPath: "out/soong/target/product/test_device/system/app/baz/baz.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux", "foo"},
- packageFlag: "org.dandroid.bp",
- renameResources: true,
- logging_parent: "",
+ name: "foo",
+ moduleName: "baz",
+ variantName: "android_common_baz",
+ apkPath: "out/soong/target/product/test_device/system/app/baz/baz.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certSigningFlags: "",
+ overrides: []string{"qux", "foo"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: true,
+ logging_parent: "",
},
{
- name: "foo",
- moduleName: "baz_no_rename_resources",
- variantName: "android_common_baz_no_rename_resources",
- apkPath: "out/soong/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux", "foo"},
- packageFlag: "org.dandroid.bp",
- renameResources: false,
- logging_parent: "",
+ name: "foo",
+ moduleName: "baz_no_rename_resources",
+ variantName: "android_common_baz_no_rename_resources",
+ apkPath: "out/soong/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certSigningFlags: "",
+ overrides: []string{"qux", "foo"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: false,
+ logging_parent: "",
},
{
- name: "foo_no_rename_resources",
- moduleName: "baz_base_no_rename_resources",
- variantName: "android_common_baz_base_no_rename_resources",
- apkPath: "out/soong/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux", "foo_no_rename_resources"},
- packageFlag: "org.dandroid.bp",
- renameResources: false,
- logging_parent: "",
+ name: "foo_no_rename_resources",
+ moduleName: "baz_base_no_rename_resources",
+ variantName: "android_common_baz_base_no_rename_resources",
+ apkPath: "out/soong/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certSigningFlags: "",
+ overrides: []string{"qux", "foo_no_rename_resources"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: false,
+ logging_parent: "",
},
{
- name: "foo_no_rename_resources",
- moduleName: "baz_override_base_rename_resources",
- variantName: "android_common_baz_override_base_rename_resources",
- apkPath: "out/soong/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux", "foo_no_rename_resources"},
- packageFlag: "org.dandroid.bp",
- renameResources: true,
- logging_parent: "",
+ name: "foo_no_rename_resources",
+ moduleName: "baz_override_base_rename_resources",
+ variantName: "android_common_baz_override_base_rename_resources",
+ apkPath: "out/soong/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ certSigningFlags: "",
+ overrides: []string{"qux", "foo_no_rename_resources"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: true,
+ logging_parent: "",
},
}
for _, expected := range expectedVariants {
@@ -1960,9 +1963,9 @@
certFlag := signapk.Args["certificates"]
android.AssertStringEquals(t, "certificates flags", expected.certFlag, certFlag)
- // Check the lineage flags
- lineageFlag := signapk.Args["flags"]
- android.AssertStringEquals(t, "signing flags", expected.lineageFlag, lineageFlag)
+ // Check the cert signing flags
+ certSigningFlags := signapk.Args["flags"]
+ android.AssertStringEquals(t, "cert signing flags", expected.certSigningFlags, certSigningFlags)
// Check if the overrides field values are correctly aggregated.
mod := variant.Module().(*AndroidApp)
@@ -2425,7 +2428,7 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
app := ctx.ModuleForTests(test.name, "android_common")
- jniLibZip := app.Output("jnilibs.zip")
+ jniLibZip := app.Output(jniJarOutputPathString)
var jnis []string
args := strings.Fields(jniLibZip.Args["jarArgs"])
for i := 0; i < len(args); i++ {
@@ -3074,3 +3077,151 @@
}
android.AssertStringDoesContain(t, "expected error rule message", fooApk.Args["error"], "missing dependencies: missing_certificate\n")
}
+
+func TestAppIncludesJniPackages(t *testing.T) {
+ ctx := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ ).RunTestWithBp(t, `
+ android_library_import {
+ name: "aary-nodeps",
+ aars: ["aary.aar"],
+ extract_jni: true,
+ }
+
+ android_library {
+ name: "aary-lib",
+ sdk_version: "current",
+ min_sdk_version: "21",
+ static_libs: ["aary-nodeps"],
+ }
+
+ android_app {
+ name: "aary-lib-dep",
+ sdk_version: "current",
+ min_sdk_version: "21",
+ manifest: "AndroidManifest.xml",
+ static_libs: ["aary-lib"],
+ use_embedded_native_libs: true,
+ }
+
+ android_app {
+ name: "aary-import-dep",
+ sdk_version: "current",
+ min_sdk_version: "21",
+ manifest: "AndroidManifest.xml",
+ static_libs: ["aary-nodeps"],
+ use_embedded_native_libs: true,
+ }
+
+ android_app {
+ name: "aary-no-use-embedded",
+ sdk_version: "current",
+ min_sdk_version: "21",
+ manifest: "AndroidManifest.xml",
+ static_libs: ["aary-nodeps"],
+ }`)
+
+ testCases := []struct {
+ name string
+ hasPackage bool
+ }{
+ {
+ name: "aary-import-dep",
+ hasPackage: true,
+ },
+ {
+ name: "aary-lib-dep",
+ hasPackage: true,
+ },
+ {
+ name: "aary-no-use-embedded",
+ hasPackage: false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ app := ctx.ModuleForTests(tc.name, "android_common")
+
+ outputFile := "jnilibs.zip"
+ jniOutputLibZip := app.MaybeOutput(outputFile)
+ if jniOutputLibZip.Rule == nil && !tc.hasPackage {
+ return
+ }
+
+ jniPackage := "arm64-v8a_jni.zip"
+ inputs := jniOutputLibZip.Inputs
+ foundPackage := false
+ for i := 0; i < len(inputs); i++ {
+ if strings.Contains(inputs[i].String(), jniPackage) {
+ foundPackage = true
+ }
+ }
+ if foundPackage != tc.hasPackage {
+ t.Errorf("expected to find %v in %v inputs; inputs = %v", jniPackage, outputFile, inputs)
+ }
+ })
+ }
+}
+
+func TestTargetSdkVersionMtsTests(t *testing.T) {
+ platformSdkCodename := "Tiramisu"
+ android_test := "android_test"
+ android_test_helper_app := "android_test_helper_app"
+ bpTemplate := `
+ %v {
+ name: "mytest",
+ target_sdk_version: "%v",
+ test_suites: ["othersuite", "%v"],
+ }
+ `
+ testCases := []struct {
+ desc string
+ moduleType string
+ targetSdkVersionInBp string
+ targetSdkVersionExpected string
+ testSuites string
+ }{
+ {
+ desc: "Non-MTS android_test_apps targeting current should not be upgraded to 10000",
+ moduleType: android_test,
+ targetSdkVersionInBp: "current",
+ targetSdkVersionExpected: platformSdkCodename,
+ testSuites: "non-mts-suite",
+ },
+ {
+ desc: "MTS android_test_apps targeting released sdks should not be upgraded to 10000",
+ moduleType: android_test,
+ targetSdkVersionInBp: "29",
+ targetSdkVersionExpected: "29",
+ testSuites: "mts-suite",
+ },
+ {
+ desc: "MTS android_test_apps targeting current should be upgraded to 10000",
+ moduleType: android_test,
+ targetSdkVersionInBp: "current",
+ targetSdkVersionExpected: "10000",
+ testSuites: "mts-suite",
+ },
+ {
+ desc: "MTS android_test_helper_apps targeting current should be upgraded to 10000",
+ moduleType: android_test_helper_app,
+ targetSdkVersionInBp: "current",
+ targetSdkVersionExpected: "10000",
+ testSuites: "mts-suite",
+ },
+ }
+ fixture := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_sdk_codename = &platformSdkCodename
+ variables.Platform_version_active_codenames = []string{platformSdkCodename}
+ }),
+ )
+ for _, testCase := range testCases {
+ result := fixture.RunTestWithBp(t, fmt.Sprintf(bpTemplate, testCase.moduleType, testCase.targetSdkVersionInBp, testCase.testSuites))
+ mytest := result.ModuleForTests("mytest", "android_common")
+ manifestFixerArgs := mytest.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ android.AssertStringDoesContain(t, testCase.desc, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
+ }
+}
diff --git a/java/base.go b/java/base.go
index 0900daa..94daf37 100644
--- a/java/base.go
+++ b/java/base.go
@@ -204,6 +204,10 @@
// Defaults to empty string "". See sdk_version for possible values.
Max_sdk_version *string
+ // if not blank, set the maxSdkVersion properties of permission and uses-permission tags.
+ // Defaults to empty string "". See sdk_version for possible values.
+ Replace_max_sdk_version_placeholder *string
+
// if not blank, set the targetSdkVersion in the AndroidManifest.xml.
// Defaults to sdk_version if not set. See sdk_version for possible values.
Target_sdk_version *string
@@ -649,6 +653,11 @@
return android.SdkSpecFrom(ctx, maxSdkVersion)
}
+func (j *Module) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.SdkSpec {
+ replaceMaxSdkVersionPlaceholder := proptools.StringDefault(j.deviceProperties.Replace_max_sdk_version_placeholder, "")
+ return android.SdkSpecFrom(ctx, replaceMaxSdkVersionPlaceholder)
+}
+
func (j *Module) MinSdkVersionString() string {
return j.minSdkVersion.Raw
}
@@ -1418,17 +1427,18 @@
j.implementationAndResourcesJar = implementationAndResourcesJar
// Enable dex compilation for the APEX variants, unless it is disabled explicitly
+ compileDex := j.dexProperties.Compile_dex
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if j.DirectlyInAnyApex() && !apexInfo.IsForPlatform() {
- if j.dexProperties.Compile_dex == nil {
- j.dexProperties.Compile_dex = proptools.BoolPtr(true)
+ if compileDex == nil {
+ compileDex = proptools.BoolPtr(true)
}
if j.deviceProperties.Hostdex == nil {
j.deviceProperties.Hostdex = proptools.BoolPtr(true)
}
}
- if ctx.Device() && (Bool(j.properties.Installable) || Bool(j.dexProperties.Compile_dex)) {
+ if ctx.Device() && (Bool(j.properties.Installable) || Bool(compileDex)) {
if j.hasCode(ctx) {
if j.shouldInstrumentStatic(ctx) {
j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles,
@@ -1484,11 +1494,30 @@
}
if ctx.Device() {
- lintSDKVersion := func(sdkSpec android.SdkSpec) android.ApiLevel {
+ lintSDKVersion := func(sdkSpec android.SdkSpec) int {
if v := sdkSpec.ApiLevel; !v.IsPreview() {
- return v
+ return v.FinalInt()
} else {
- return ctx.Config().DefaultAppTargetSdk(ctx)
+ // When running metalava, we pass --version-codename. When that value
+ // is not REL, metalava will add 1 to the --current-version argument.
+ // On old branches, PLATFORM_SDK_VERSION is the latest version (for that
+ // branch) and the codename is REL, except potentially on the most
+ // recent non-master branch. On that branch, it goes through two other
+ // phases before it gets to the phase previously described:
+ // - PLATFORM_SDK_VERSION has not been updated yet, and the codename
+ // is not rel. This happens for most of the internal branch's life
+ // while the branch has been cut but is still under active development.
+ // - PLATFORM_SDK_VERSION has been set, but the codename is still not
+ // REL. This happens briefly during the release process. During this
+ // state the code to add --current-version is commented out, and then
+ // that commenting out is reverted after the codename is set to REL.
+ // On the master branch, the PLATFORM_SDK_VERSION always represents a
+ // prior version and the codename is always non-REL.
+ //
+ // We need to add one here to match metalava adding 1. Technically
+ // this means that in the state described in the second bullet point
+ // above, this number is 1 higher than it should be.
+ return ctx.Config().PlatformSdkVersion().FinalInt() + 1
}
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 0345aad..56401b3 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -32,19 +32,24 @@
func init() {
registerBootclasspathFragmentBuildComponents(android.InitRegistrationContext)
- android.RegisterSdkMemberType(&bootclasspathFragmentMemberType{
- SdkMemberTypeBase: android.SdkMemberTypeBase{
- PropertyName: "bootclasspath_fragments",
- SupportsSdk: true,
- },
- })
+ android.RegisterSdkMemberType(BootclasspathFragmentSdkMemberType)
}
func registerBootclasspathFragmentBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("bootclasspath_fragment", bootclasspathFragmentFactory)
+ ctx.RegisterModuleType("bootclasspath_fragment_test", testBootclasspathFragmentFactory)
ctx.RegisterModuleType("prebuilt_bootclasspath_fragment", prebuiltBootclasspathFragmentFactory)
}
+// BootclasspathFragmentSdkMemberType is the member type used to add bootclasspath_fragments to
+// the SDK snapshot. It is exported for use by apex.
+var BootclasspathFragmentSdkMemberType = &bootclasspathFragmentMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "bootclasspath_fragments",
+ SupportsSdk: true,
+ },
+}
+
type bootclasspathFragmentContentDependencyTag struct {
blueprint.BaseDependencyTag
}
@@ -227,6 +232,9 @@
android.SdkBase
ClasspathFragmentBase
+ // True if this fragment is for testing purposes.
+ testFragment bool
+
properties bootclasspathFragmentProperties
sourceOnlyProperties SourceOnlyBootclasspathProperties
@@ -298,6 +306,12 @@
return m
}
+func testBootclasspathFragmentFactory() android.Module {
+ m := bootclasspathFragmentFactory().(*BootclasspathFragmentModule)
+ m.testFragment = true
+ return m
+}
+
// bootclasspathFragmentInitContentsFromImage will initialize the contents property from the image_name if
// necessary.
func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, m *BootclasspathFragmentModule) {
@@ -709,6 +723,10 @@
} else if global.ApexBootJars.Len() != 0 && !android.IsModuleInVersionedSdk(ctx.Module()) {
unknown = android.RemoveListFromList(unknown, b.properties.Coverage.Contents)
_, unknown = android.RemoveFromList("core-icu4j", unknown)
+ // This module only exists in car products.
+ // So ignore it even if it is not in PRODUCT_APEX_BOOT_JARS.
+ // TODO(b/202896428): Add better way to handle this.
+ _, unknown = android.RemoveFromList("android.car-module", unknown)
if len(unknown) > 0 {
ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown)
}
@@ -815,6 +833,26 @@
return input
}
+// isTestFragment returns true if the current module is a test bootclasspath_fragment.
+func (b *BootclasspathFragmentModule) isTestFragment() bool {
+ if b.testFragment {
+ return true
+ }
+
+ // TODO(b/194063708): Once test fragments all use bootclasspath_fragment_test
+ // Some temporary exceptions until all test fragments use the
+ // bootclasspath_fragment_test module type.
+ name := b.BaseModuleName()
+ if strings.HasPrefix(name, "test_") {
+ return true
+ }
+ if name == "apex.apexd_test_bootclasspath-fragment" {
+ return true
+ }
+
+ return false
+}
+
// produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files)
// for the fragment as well as encoding the flags in the boot dex jars.
func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
@@ -828,11 +866,18 @@
packagePrefixes := b.sourceOnlyProperties.Hidden_api.Package_prefixes
singlePackages := b.sourceOnlyProperties.Hidden_api.Single_packages
if splitPackages != nil || packagePrefixes != nil || singlePackages != nil {
- if splitPackages == nil {
- splitPackages = []string{"*"}
- }
output.SignaturePatternsPath = buildRuleSignaturePatternsFile(
ctx, output.AllFlagsPath, splitPackages, packagePrefixes, singlePackages)
+ } else if !b.isTestFragment() {
+ ctx.ModuleErrorf(`Must specify at least one of the split_packages, package_prefixes and single_packages properties
+ If this is a new bootclasspath_fragment or you are unsure what to do add the
+ the following to the bootclasspath_fragment:
+ hidden_api: {split_packages: ["*"]},
+ and then run the following:
+ m analyze_bcpf && analyze_bcpf --bcpf %q
+ it will analyze the bootclasspath_fragment and provide hints as to what you
+ should specify here. If you are happy with its suggestions then you can add
+ the --fix option and it will fix them for you.`, b.BaseModuleName())
}
return output
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index d3de675..83beb6d 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -121,6 +121,9 @@
],
},
},
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -201,6 +204,9 @@
core_platform_api: {
stub_libs: ["mycoreplatform.stubs"],
},
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -278,3 +284,64 @@
android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope())
}
+
+func TestBootclasspathFragment_Test(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithBootclasspathFragment,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("mysdklibrary"),
+ ).RunTestWithBp(t, `
+ bootclasspath_fragment {
+ name: "myfragment",
+ contents: ["mysdklibrary"],
+ hidden_api: {
+ split_packages: [],
+ },
+ }
+
+ bootclasspath_fragment {
+ name: "test_fragment",
+ contents: ["mysdklibrary"],
+ hidden_api: {
+ split_packages: [],
+ },
+ }
+
+ bootclasspath_fragment {
+ name: "apex.apexd_test_bootclasspath-fragment",
+ contents: ["mysdklibrary"],
+ hidden_api: {
+ split_packages: [],
+ },
+ }
+
+ bootclasspath_fragment_test {
+ name: "a_test_fragment",
+ contents: ["mysdklibrary"],
+ hidden_api: {
+ split_packages: [],
+ },
+ }
+
+
+ java_sdk_library {
+ name: "mysdklibrary",
+ srcs: ["a.java"],
+ shared_library: false,
+ public: {enabled: true},
+ system: {enabled: true},
+ }
+ `)
+
+ fragment := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule)
+ android.AssertBoolEquals(t, "not a test fragment", false, fragment.isTestFragment())
+
+ fragment = result.Module("test_fragment", "android_common").(*BootclasspathFragmentModule)
+ android.AssertBoolEquals(t, "is a test fragment by prefix", true, fragment.isTestFragment())
+
+ fragment = result.Module("a_test_fragment", "android_common").(*BootclasspathFragmentModule)
+ android.AssertBoolEquals(t, "is a test fragment by type", true, fragment.isTestFragment())
+
+ fragment = result.Module("apex.apexd_test_bootclasspath-fragment", "android_common").(*BootclasspathFragmentModule)
+ android.AssertBoolEquals(t, "is a test fragment by name", true, fragment.isTestFragment())
+}
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index ca27528..259e977 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -131,14 +131,14 @@
// TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
if s.minSdkVersion.Specified() {
if s.minSdkVersion.ApiLevel.IsCurrent() {
- jar.minSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
+ jar.minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
} else {
jar.minSdkVersion = s.minSdkVersion.ApiLevel.String()
}
}
if s.maxSdkVersion.Specified() {
if s.maxSdkVersion.ApiLevel.IsCurrent() {
- jar.maxSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
+ jar.maxSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
} else {
jar.maxSdkVersion = s.maxSdkVersion.ApiLevel.String()
}
diff --git a/java/config/config.go b/java/config/config.go
index d744002..3ca9bad 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -89,12 +89,14 @@
// D8 invocations are shorter lived, so we restrict their JIT tiering relative to R8.
// Note that the `-JXX` prefix syntax is specific to the R8/D8 invocation wrappers.
exportedVars.ExportStringListStaticVariable("D8Flags", append([]string{
- "-JXmx2048M",
+ "-JXmx4096M",
"-JXX:+TieredCompilation",
"-JXX:TieredStopAtLevel=1",
}, dexerJavaVmFlagsList...))
exportedVars.ExportStringListStaticVariable("R8Flags", append([]string{
"-JXmx2048M",
+ // Disable this optimization as it can impact weak reference semantics. See b/233432839.
+ "-JDcom.android.tools.r8.disableEnqueuerDeferredTracing=true",
}, dexerJavaVmFlagsList...))
exportedVars.ExportStringListStaticVariable("CommonJdkFlags", []string{
@@ -157,7 +159,7 @@
pctx.HostBinToolVariable("ZipSyncCmd", "zipsync")
pctx.HostBinToolVariable("ApiCheckCmd", "apicheck")
pctx.HostBinToolVariable("D8Cmd", "d8")
- pctx.HostBinToolVariable("R8Cmd", "r8-compat-proguard")
+ pctx.HostBinToolVariable("R8Cmd", "r8")
pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi")
pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks")
pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string {
@@ -175,7 +177,7 @@
pctx.HostJavaToolVariable("MetalavaJar", "metalava.jar")
pctx.HostJavaToolVariable("DokkaJar", "dokka.jar")
pctx.HostJavaToolVariable("JetifierJar", "jetifier.jar")
- pctx.HostJavaToolVariable("R8Jar", "r8-compat-proguard.jar")
+ pctx.HostJavaToolVariable("R8Jar", "r8.jar")
pctx.HostJavaToolVariable("D8Jar", "d8.jar")
pctx.HostBinToolVariable("SoongJavacWrapper", "soong_javac_wrapper")
diff --git a/java/dex.go b/java/dex.go
index 13d6e4a..a44d792 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -36,12 +36,15 @@
Main_dex_rules []string `android:"path"`
Optimize struct {
- // If false, disable all optimization. Defaults to true for android_app and android_test
- // modules, false for java_library and java_test modules.
+ // If false, disable all optimization. Defaults to true for android_app and
+ // android_test_helper_app modules, false for android_test, java_library, and java_test modules.
Enabled *bool
// True if the module containing this has it set by default.
EnabledByDefault bool `blueprint:"mutated"`
+ // Whether to continue building even if warnings are emitted. Defaults to true.
+ Ignore_warnings *bool
+
// If true, runs R8 in Proguard compatibility mode (default).
// Otherwise, runs R8 in full mode.
Proguard_compatibility *bool
@@ -293,7 +296,10 @@
}
// TODO(b/180878971): missing classes should be added to the relevant builds.
- r8Flags = append(r8Flags, "-ignorewarnings")
+ // TODO(b/229727645): do not use true as default for Android platform builds.
+ if proptools.BoolDefault(opt.Ignore_warnings, true) {
+ r8Flags = append(r8Flags, "-ignorewarnings")
+ }
return r8Flags, r8Deps
}
diff --git a/java/dex_test.go b/java/dex_test.go
index fbdccb6..a3e2ded 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -59,6 +59,36 @@
appR8.Args["r8Flags"], libHeader.String())
android.AssertStringDoesNotContain(t, "expected no static_lib header jar in app javac classpath",
appR8.Args["r8Flags"], staticLibHeader.String())
+ android.AssertStringDoesContain(t, "expected -ignorewarnings in app r8 flags",
+ appR8.Args["r8Flags"], "-ignorewarnings")
+}
+
+func TestR8Flags(t *testing.T) {
+ result := PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd.RunTestWithBp(t, `
+ android_app {
+ name: "app",
+ srcs: ["foo.java"],
+ platform_apis: true,
+ optimize: {
+ shrink: false,
+ optimize: false,
+ obfuscate: false,
+ ignore_warnings: false,
+ },
+ }
+ `)
+
+ app := result.ModuleForTests("app", "android_common")
+ appR8 := app.Rule("r8")
+ android.AssertStringDoesContain(t, "expected -dontshrink in app r8 flags",
+ appR8.Args["r8Flags"], "-dontshrink")
+ android.AssertStringDoesContain(t, "expected -dontoptimize in app r8 flags",
+ appR8.Args["r8Flags"], "-dontoptimize")
+ android.AssertStringDoesContain(t, "expected -dontobfuscate in app r8 flags",
+ appR8.Args["r8Flags"], "-dontobfuscate")
+ android.AssertStringDoesNotContain(t, "expected no -ignorewarnings in app r8 flags",
+ appR8.Args["r8Flags"], "-ignorewarnings")
+
}
func TestD8(t *testing.T) {
diff --git a/java/dexpreopt.go_v1 b/java/dexpreopt.go_v1
deleted file mode 100644
index 0adaf99..0000000
--- a/java/dexpreopt.go_v1
+++ /dev/null
@@ -1,404 +0,0 @@
-// Copyright 2018 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 java
-
-import (
- "path/filepath"
- "strings"
-
- "android/soong/android"
- "android/soong/dexpreopt"
-)
-
-type DexpreopterInterface interface {
- IsInstallable() bool // Structs that embed dexpreopter must implement this.
- dexpreoptDisabled(ctx android.BaseModuleContext) bool
- DexpreoptBuiltInstalledForApex() []dexpreopterInstall
- AndroidMkEntriesForApex() []android.AndroidMkEntries
-}
-
-type dexpreopterInstall struct {
- // A unique name to distinguish an output from others for the same java library module. Usually in
- // the form of `<arch>-<encoded-path>.odex/vdex/art`.
- name string
-
- // The name of the input java module.
- moduleName string
-
- // The path to the dexpreopt output on host.
- outputPathOnHost android.Path
-
- // The directory on the device for the output to install to.
- installDirOnDevice android.InstallPath
-
- // The basename (the last segment of the path) for the output to install as.
- installFileOnDevice string
-}
-
-// The full module name of the output in the makefile.
-func (install *dexpreopterInstall) FullModuleName() string {
- return install.moduleName + install.SubModuleName()
-}
-
-// The sub-module name of the output in the makefile (the name excluding the java module name).
-func (install *dexpreopterInstall) SubModuleName() string {
- return "-dexpreopt-" + install.name
-}
-
-// Returns Make entries for installing the file.
-//
-// This function uses a value receiver rather than a pointer receiver to ensure that the object is
-// safe to use in `android.AndroidMkExtraEntriesFunc`.
-func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
- return android.AndroidMkEntries{
- Class: "ETC",
- SubName: install.SubModuleName(),
- OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
- entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
- entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
- },
- },
- }
-}
-
-type dexpreopter struct {
- dexpreoptProperties DexpreoptProperties
-
- installPath android.InstallPath
- uncompressedDex bool
- isSDKLibrary bool
- isApp bool
- isTest bool
- isPresignedPrebuilt bool
- preventInstall bool
-
- manifestFile android.Path
- statusFile android.WritablePath
- enforceUsesLibs bool
- classLoaderContexts dexpreopt.ClassLoaderContextMap
-
- // See the `dexpreopt` function for details.
- builtInstalled string
- builtInstalledForApex []dexpreopterInstall
-
- // The config is used for two purposes:
- // - Passing dexpreopt information about libraries from Soong to Make. This is needed when
- // a <uses-library> is defined in Android.bp, but used in Android.mk (see dex_preopt_config_merger.py).
- // Note that dexpreopt.config might be needed even if dexpreopt is disabled for the library itself.
- // - Dexpreopt post-processing (using dexpreopt artifacts from a prebuilt system image to incrementally
- // dexpreopt another partition).
- configPath android.WritablePath
-}
-
-type DexpreoptProperties struct {
- Dex_preopt struct {
- // If false, prevent dexpreopting. Defaults to true.
- Enabled *bool
-
- // If true, generate an app image (.art file) for this module.
- App_image *bool
-
- // If true, use a checked-in profile to guide optimization. Defaults to false unless
- // a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR
- // that matches the name of this module, in which case it is defaulted to true.
- Profile_guided *bool
-
- // If set, provides the path to profile relative to the Android.bp file. If not set,
- // defaults to searching for a file that matches the name of this module in the default
- // profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found.
- Profile *string `android:"path"`
- }
-}
-
-func init() {
- dexpreopt.DexpreoptRunningInSoong = true
-}
-
-func isApexVariant(ctx android.BaseModuleContext) bool {
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
- return !apexInfo.IsForPlatform()
-}
-
-func forPrebuiltApex(ctx android.BaseModuleContext) bool {
- apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
- return apexInfo.ForPrebuiltApex
-}
-
-func moduleName(ctx android.BaseModuleContext) string {
- // Remove the "prebuilt_" prefix if the module is from a prebuilt because the prefix is not
- // expected by dexpreopter.
- return android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName())
-}
-
-func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
- if !ctx.Device() {
- return true
- }
-
- if d.isTest {
- return true
- }
-
- if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) {
- return true
- }
-
- // If the module is from a prebuilt APEX, it shouldn't be installable, but it can still be
- // dexpreopted.
- if !ctx.Module().(DexpreopterInterface).IsInstallable() && !forPrebuiltApex(ctx) {
- return true
- }
-
- if !android.IsModulePreferred(ctx.Module()) {
- return true
- }
-
- global := dexpreopt.GetGlobalConfig(ctx)
-
- if global.DisablePreopt {
- return true
- }
-
- if inList(moduleName(ctx), global.DisablePreoptModules) {
- return true
- }
-
- isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
- if isApexVariant(ctx) {
- // Don't preopt APEX variant module unless the module is an APEX system server jar and we are
- // building the entire system image.
- if !isApexSystemServerJar || ctx.Config().UnbundledBuild() {
- return true
- }
- } else {
- // Don't preopt the platform variant of an APEX system server jar to avoid conflicts.
- if isApexSystemServerJar {
- return true
- }
- }
-
- // TODO: contains no java code
-
- return false
-}
-
-func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) {
- if d, ok := ctx.Module().(DexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) {
- return
- }
- dexpreopt.RegisterToolDeps(ctx)
-}
-
-func (d *dexpreopter) odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
- return dexpreopt.OdexOnSystemOtherByName(moduleName(ctx), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
-}
-
-// Returns the install path of the dex jar of a module.
-//
-// Do not rely on `ApexInfo.ApexVariationName` because it can be something like "apex1000", rather
-// than the `name` in the path `/apex/<name>` as suggested in its comment.
-//
-// This function is on a best-effort basis. It cannot handle the case where an APEX jar is not a
-// system server jar, which is fine because we currently only preopt system server jars for APEXes.
-func (d *dexpreopter) getInstallPath(
- ctx android.ModuleContext, defaultInstallPath android.InstallPath) android.InstallPath {
- global := dexpreopt.GetGlobalConfig(ctx)
- if global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx)) {
- dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, moduleName(ctx))
- return android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexLocation, "/"))
- }
- if !d.dexpreoptDisabled(ctx) && isApexVariant(ctx) &&
- filepath.Base(defaultInstallPath.PartitionDir()) != "apex" {
- ctx.ModuleErrorf("unable to get the install path of the dex jar for dexpreopt")
- }
- return defaultInstallPath
-}
-
-func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) {
- global := dexpreopt.GetGlobalConfig(ctx)
-
- // TODO(b/148690468): The check on d.installPath is to bail out in cases where
- // the dexpreopter struct hasn't been fully initialized before we're called,
- // e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively
- // disabled, even if installable is true.
- if d.installPath.Base() == "." {
- return
- }
-
- dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
-
- providesUsesLib := moduleName(ctx)
- if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
- name := ulib.ProvidesUsesLib()
- if name != nil {
- providesUsesLib = *name
- }
- }
-
- // If it is test, make config files regardless of its dexpreopt setting.
- // The config files are required for apps defined in make which depend on the lib.
- if d.isTest && d.dexpreoptDisabled(ctx) {
- return
- }
-
- isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(moduleName(ctx))
-
- bootImage := defaultBootImageConfig(ctx)
- dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
-
- targets := ctx.MultiTargets()
- if len(targets) == 0 {
- // assume this is a java library, dexpreopt for all arches for now
- for _, target := range ctx.Config().Targets[android.Android] {
- if target.NativeBridge == android.NativeBridgeDisabled {
- targets = append(targets, target)
- }
- }
- if isSystemServerJar && !d.isSDKLibrary {
- // If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
- targets = targets[:1]
- }
- }
-
- var archs []android.ArchType
- var images android.Paths
- var imagesDeps []android.OutputPaths
- for _, target := range targets {
- archs = append(archs, target.Arch.ArchType)
- variant := bootImage.getVariant(target)
- images = append(images, variant.imagePathOnHost)
- imagesDeps = append(imagesDeps, variant.imagesDeps)
- }
- // The image locations for all Android variants are identical.
- hostImageLocations, deviceImageLocations := bootImage.getAnyAndroidVariant().imageLocations()
-
- var profileClassListing android.OptionalPath
- var profileBootListing android.OptionalPath
- profileIsTextListing := false
- if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) {
- // If dex_preopt.profile_guided is not set, default it based on the existence of the
- // dexprepot.profile option or the profile class listing.
- if String(d.dexpreoptProperties.Dex_preopt.Profile) != "" {
- profileClassListing = android.OptionalPathForPath(
- android.PathForModuleSrc(ctx, String(d.dexpreoptProperties.Dex_preopt.Profile)))
- profileBootListing = android.ExistentPathForSource(ctx,
- ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot")
- profileIsTextListing = true
- } else if global.ProfileDir != "" {
- profileClassListing = android.ExistentPathForSource(ctx,
- global.ProfileDir, moduleName(ctx)+".prof")
- }
- }
-
- // Full dexpreopt config, used to create dexpreopt build rules.
- dexpreoptConfig := &dexpreopt.ModuleConfig{
- Name: moduleName(ctx),
- DexLocation: dexLocation,
- BuildPath: android.PathForModuleOut(ctx, "dexpreopt", moduleName(ctx)+".jar").OutputPath,
- DexPath: dexJarFile,
- ManifestPath: android.OptionalPathForPath(d.manifestFile),
- UncompressedDex: d.uncompressedDex,
- HasApkLibraries: false,
- PreoptFlags: nil,
-
- ProfileClassListing: profileClassListing,
- ProfileIsTextListing: profileIsTextListing,
- ProfileBootListing: profileBootListing,
-
- EnforceUsesLibrariesStatusFile: dexpreopt.UsesLibrariesStatusFile(ctx),
- EnforceUsesLibraries: d.enforceUsesLibs,
- ProvidesUsesLibrary: providesUsesLib,
- ClassLoaderContexts: d.classLoaderContexts,
-
- Archs: archs,
- DexPreoptImagesDeps: imagesDeps,
- DexPreoptImageLocationsOnHost: hostImageLocations,
- DexPreoptImageLocationsOnDevice: deviceImageLocations,
-
- PreoptBootClassPathDexFiles: dexFiles.Paths(),
- PreoptBootClassPathDexLocations: dexLocations,
-
- PreoptExtractedApk: false,
-
- NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
- ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
-
- PresignedPrebuilt: d.isPresignedPrebuilt,
- }
-
- d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config")
- dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath)
-
- if d.dexpreoptDisabled(ctx) {
- return
- }
-
- globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
-
- dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig)
- if err != nil {
- ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
- return
- }
-
- dexpreoptRule.Build("dexpreopt", "dexpreopt")
-
- isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
-
- for _, install := range dexpreoptRule.Installs() {
- // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
- installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
- installBase := filepath.Base(install.To)
- arch := filepath.Base(installDir)
- installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
-
- if isApexSystemServerJar {
- // APEX variants of java libraries are hidden from Make, so their dexpreopt
- // outputs need special handling. Currently, for APEX variants of java
- // libraries, only those in the system server classpath are handled here.
- // Preopting of boot classpath jars in the ART APEX are handled in
- // java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
- // The installs will be handled by Make as sub-modules of the java library.
- d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
- name: arch + "-" + installBase,
- moduleName: moduleName(ctx),
- outputPathOnHost: install.From,
- installDirOnDevice: installPath,
- installFileOnDevice: installBase,
- })
- } else if !d.preventInstall {
- ctx.InstallFile(installPath, installBase, install.From)
- }
- }
-
- if !isApexSystemServerJar {
- d.builtInstalled = dexpreoptRule.Installs().String()
- }
-}
-
-func (d *dexpreopter) DexpreoptBuiltInstalledForApex() []dexpreopterInstall {
- return d.builtInstalledForApex
-}
-
-func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries {
- var entries []android.AndroidMkEntries
- for _, install := range d.builtInstalledForApex {
- entries = append(entries, install.ToMakeEntries())
- }
- return entries
-}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 7c4da3e..b4cd07a 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -785,24 +785,26 @@
}
defaultProfile := "frameworks/base/config/boot-image-profile.txt"
+ extraProfile := "frameworks/base/config/boot-image-profile-extra.txt"
rule := android.NewRuleBuilder(pctx, ctx)
- var bootImageProfile android.Path
- if len(global.BootImageProfiles) > 1 {
- combinedBootImageProfile := image.dir.Join(ctx, "boot-image-profile.txt")
- rule.Command().Text("cat").Inputs(global.BootImageProfiles).Text(">").Output(combinedBootImageProfile)
- bootImageProfile = combinedBootImageProfile
- } else if len(global.BootImageProfiles) == 1 {
- bootImageProfile = global.BootImageProfiles[0]
+ var profiles android.Paths
+ if len(global.BootImageProfiles) > 0 {
+ profiles = append(profiles, global.BootImageProfiles...)
} else if path := android.ExistentPathForSource(ctx, defaultProfile); path.Valid() {
- bootImageProfile = path.Path()
+ profiles = append(profiles, path.Path())
} else {
// No profile (not even a default one, which is the case on some branches
// like master-art-host that don't have frameworks/base).
// Return nil and continue without profile.
return nil
}
+ if path := android.ExistentPathForSource(ctx, extraProfile); path.Valid() {
+ profiles = append(profiles, path.Path())
+ }
+ bootImageProfile := image.dir.Join(ctx, "boot-image-profile.txt")
+ rule.Command().Text("cat").Inputs(profiles).Text(">").Output(bootImageProfile)
profile := image.dir.Join(ctx, "boot.prof")
diff --git a/java/dexpreopt_bootjars.go_v1 b/java/dexpreopt_bootjars.go_v1
deleted file mode 100644
index 07a357b..0000000
--- a/java/dexpreopt_bootjars.go_v1
+++ /dev/null
@@ -1,952 +0,0 @@
-// Copyright 2019 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 java
-
-import (
- "path/filepath"
- "strings"
-
- "android/soong/android"
- "android/soong/dexpreopt"
-
- "github.com/google/blueprint/proptools"
-)
-
-// =================================================================================================
-// WIP - see http://b/177892522 for details
-//
-// The build support for boot images is currently being migrated away from singleton to modules so
-// the documentation may not be strictly accurate. Rather than update the documentation at every
-// step which will create a lot of churn the changes that have been made will be listed here and the
-// documentation will be updated once it is closer to the final result.
-//
-// Changes:
-// 1) dex_bootjars is now a singleton module and not a plain singleton.
-// 2) Boot images are now represented by the boot_image module type.
-// 3) The art boot image is called "art-boot-image", the framework boot image is called
-// "framework-boot-image".
-// 4) They are defined in art/build/boot/Android.bp and frameworks/base/boot/Android.bp
-// respectively.
-// 5) Each boot_image retrieves the appropriate boot image configuration from the map returned by
-// genBootImageConfigs() using the image_name specified in the boot_image module.
-// =================================================================================================
-
-// This comment describes:
-// 1. ART boot images in general (their types, structure, file layout, etc.)
-// 2. build system support for boot images
-//
-// 1. ART boot images
-// ------------------
-//
-// A boot image in ART is a set of files that contain AOT-compiled native code and a heap snapshot
-// of AOT-initialized classes for the bootclasspath Java libraries. A boot image is compiled from a
-// set of DEX jars by the dex2oat compiler. A boot image is used for two purposes: 1) it is
-// installed on device and loaded at runtime, and 2) other Java libraries and apps are compiled
-// against it (compilation may take place either on host, known as "dexpreopt", or on device, known
-// as "dexopt").
-//
-// A boot image is not a single file, but a collection of interrelated files. Each boot image has a
-// number of components that correspond to the Java libraries that constitute it. For each component
-// there are multiple files:
-// - *.oat or *.odex file with native code (architecture-specific, one per instruction set)
-// - *.art file with pre-initialized Java classes (architecture-specific, one per instruction set)
-// - *.vdex file with verification metadata for the DEX bytecode (architecture independent)
-//
-// *.vdex files for the boot images do not contain the DEX bytecode itself, because the
-// bootclasspath DEX files are stored on disk in uncompressed and aligned form. Consequently a boot
-// image is not self-contained and cannot be used without its DEX files. To simplify the management
-// of boot image files, ART uses a certain naming scheme and associates the following metadata with
-// each boot image:
-// - A stem, which is a symbolic name that is prepended to boot image file names.
-// - A location (on-device path to the boot image files).
-// - A list of boot image locations (on-device paths to dependency boot images).
-// - A set of DEX locations (on-device paths to the DEX files, one location for one DEX file used
-// to compile the boot image).
-//
-// There are two kinds of boot images:
-// - primary boot images
-// - boot image extensions
-//
-// 1.1. Primary boot images
-// ------------------------
-//
-// A primary boot image is compiled for a core subset of bootclasspath Java libraries. It does not
-// depend on any other images, and other boot images may depend on it.
-//
-// For example, assuming that the stem is "boot", the location is /apex/com.android.art/javalib/,
-// the set of core bootclasspath libraries is A B C, and the boot image is compiled for ARM targets
-// (32 and 64 bits), it will have three components with the following files:
-// - /apex/com.android.art/javalib/{arm,arm64}/boot.{art,oat,vdex}
-// - /apex/com.android.art/javalib/{arm,arm64}/boot-B.{art,oat,vdex}
-// - /apex/com.android.art/javalib/{arm,arm64}/boot-C.{art,oat,vdex}
-//
-// The files of the first component are special: they do not have the component name appended after
-// the stem. This naming convention dates back to the times when the boot image was not split into
-// components, and there were just boot.oat and boot.art. The decision to split was motivated by
-// licensing reasons for one of the bootclasspath libraries.
-//
-// As of November 2020 the only primary boot image in Android is the image in the ART APEX
-// com.android.art. The primary ART boot image contains the Core libraries that are part of the ART
-// module. When the ART module gets updated, the primary boot image will be updated with it, and all
-// dependent images will get invalidated (the checksum of the primary image stored in dependent
-// images will not match), unless they are updated in sync with the ART module.
-//
-// 1.2. Boot image extensions
-// --------------------------
-//
-// A boot image extension is compiled for a subset of bootclasspath Java libraries (in particular,
-// this subset does not include the Core bootclasspath libraries that go into the primary boot
-// image). A boot image extension depends on the primary boot image and optionally some other boot
-// image extensions. Other images may depend on it. In other words, boot image extensions can form
-// acyclic dependency graphs.
-//
-// The motivation for boot image extensions comes from the Mainline project. Consider a situation
-// when the list of bootclasspath libraries is A B C, and both A and B are parts of the Android
-// platform, but C is part of an updatable APEX com.android.C. When the APEX is updated, the Java
-// code for C might have changed compared to the code that was used to compile the boot image.
-// Consequently, the whole boot image is obsolete and invalidated (even though the code for A and B
-// that does not depend on C is up to date). To avoid this, the original monolithic boot image is
-// split in two parts: the primary boot image that contains A B, and the boot image extension that
-// contains C and depends on the primary boot image (extends it).
-//
-// For example, assuming that the stem is "boot", the location is /system/framework, the set of
-// bootclasspath libraries is D E (where D is part of the platform and is located in
-// /system/framework, and E is part of a non-updatable APEX com.android.E and is located in
-// /apex/com.android.E/javalib), and the boot image is compiled for ARM targets (32 and 64 bits),
-// it will have two components with the following files:
-// - /system/framework/{arm,arm64}/boot-D.{art,oat,vdex}
-// - /system/framework/{arm,arm64}/boot-E.{art,oat,vdex}
-//
-// As of November 2020 the only boot image extension in Android is the Framework boot image
-// extension. It extends the primary ART boot image and contains Framework libraries and other
-// bootclasspath libraries from the platform and non-updatable APEXes that are not included in the
-// ART image. The Framework boot image extension is updated together with the platform. In the
-// future other boot image extensions may be added for some updatable modules.
-//
-//
-// 2. Build system support for boot images
-// ---------------------------------------
-//
-// The primary ART boot image needs to be compiled with one dex2oat invocation that depends on DEX
-// jars for the core libraries. Framework boot image extension needs to be compiled with one dex2oat
-// invocation that depends on the primary ART boot image and all bootclasspath DEX jars except the
-// core libraries as they are already part of the primary ART boot image.
-//
-// 2.1. Libraries that go in the boot images
-// -----------------------------------------
-//
-// The contents of each boot image are determined by the PRODUCT variables. The primary ART APEX
-// boot image contains libraries listed in the ART_APEX_JARS variable in the AOSP makefiles. The
-// Framework boot image extension contains libraries specified in the PRODUCT_BOOT_JARS and
-// PRODUCT_BOOT_JARS_EXTRA variables. The AOSP makefiles specify some common Framework libraries,
-// but more product-specific libraries can be added in the product makefiles.
-//
-// Each component of the PRODUCT_BOOT_JARS and PRODUCT_BOOT_JARS_EXTRA variables is a
-// colon-separated pair <apex>:<library>, where <apex> is the variant name of a non-updatable APEX,
-// "platform" if the library is a part of the platform in the system partition, or "system_ext" if
-// it's in the system_ext partition.
-//
-// In these variables APEXes are identified by their "variant names", i.e. the names they get
-// mounted as in /apex on device. In Soong modules that is the name set in the "apex_name"
-// properties, which default to the "name" values. For example, many APEXes have both
-// com.android.xxx and com.google.android.xxx modules in Soong, but take the same place
-// /apex/com.android.xxx at runtime. In these cases the variant name is always com.android.xxx,
-// regardless which APEX goes into the product. See also android.ApexInfo.ApexVariationName and
-// apex.apexBundleProperties.Apex_name.
-//
-// A related variable PRODUCT_APEX_BOOT_JARS contains bootclasspath libraries that are in APEXes.
-// They are not included in the boot image. The only exception here are ART jars and core-icu4j.jar
-// that have been historically part of the boot image and are now in apexes; they are in boot images
-// and core-icu4j.jar is generally treated as being part of PRODUCT_BOOT_JARS.
-//
-// One exception to the above rules are "coverage" builds (a special build flavor which requires
-// setting environment variable EMMA_INSTRUMENT_FRAMEWORK=true). In coverage builds the Java code in
-// boot image libraries is instrumented, which means that the instrumentation library (jacocoagent)
-// needs to be added to the list of bootclasspath DEX jars.
-//
-// In general, there is a requirement that the source code for a boot image library must be
-// available at build time (e.g. it cannot be a stub that has a separate implementation library).
-//
-// 2.2. Static configs
-// -------------------
-//
-// Because boot images are used to dexpreopt other Java modules, the paths to boot image files must
-// be known by the time dexpreopt build rules for the dependent modules are generated. Boot image
-// configs are constructed very early during the build, before build rule generation. The configs
-// provide predefined paths to boot image files (these paths depend only on static build
-// configuration, such as PRODUCT variables, and use hard-coded directory names).
-//
-// 2.3. Singleton
-// --------------
-//
-// Build rules for the boot images are generated with a Soong singleton. Because a singleton has no
-// dependencies on other modules, it has to find the modules for the DEX jars using VisitAllModules.
-// Soong loops through all modules and compares each module against a list of bootclasspath library
-// names. Then it generates build rules that copy DEX jars from their intermediate module-specific
-// locations to the hard-coded locations predefined in the boot image configs.
-//
-// It would be possible to use a module with proper dependencies instead, but that would require
-// changes in the way Soong generates variables for Make: a singleton can use one MakeVars() method
-// that writes variables to out/soong/make_vars-*.mk, which is included early by the main makefile,
-// but module(s) would have to use out/soong/Android-*.mk which has a group of LOCAL_* variables
-// for each module, and is included later.
-//
-// 2.4. Install rules
-// ------------------
-//
-// The primary boot image and the Framework extension are installed in different ways. The primary
-// boot image is part of the ART APEX: it is copied into the APEX intermediate files, packaged
-// together with other APEX contents, extracted and mounted on device. The Framework boot image
-// extension is installed by the rules defined in makefiles (make/core/dex_preopt_libart.mk). Soong
-// writes out a few DEXPREOPT_IMAGE_* variables for Make; these variables contain boot image names,
-// paths and so on.
-//
-
-var artApexNames = []string{
- "com.android.art",
- "com.android.art.debug",
- "com.android.art.testing",
- "com.google.android.art",
- "com.google.android.art.debug",
- "com.google.android.art.testing",
-}
-
-func init() {
- RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
-}
-
-// Target-independent description of a boot image.
-type bootImageConfig struct {
- // If this image is an extension, the image that it extends.
- extends *bootImageConfig
-
- // Image name (used in directory names and ninja rule names).
- name string
-
- // Basename of the image: the resulting filenames are <stem>[-<jar>].{art,oat,vdex}.
- stem string
-
- // Output directory for the image files.
- dir android.OutputPath
-
- // Output directory for the image files with debug symbols.
- symbolsDir android.OutputPath
-
- // Subdirectory where the image files are installed.
- installDirOnHost string
-
- // Subdirectory where the image files on device are installed.
- installDirOnDevice string
-
- // Install path of the boot image profile if it needs to be installed in the APEX, or empty if not
- // needed.
- profileInstallPathInApex string
-
- // A list of (location, jar) pairs for the Java modules in this image.
- modules android.ConfiguredJarList
-
- // File paths to jars.
- dexPaths android.WritablePaths // for this image
- dexPathsDeps android.WritablePaths // for the dependency images and in this image
-
- // Map from module name (without prebuilt_ prefix) to the predefined build path.
- dexPathsByModule map[string]android.WritablePath
-
- // File path to a zip archive with all image files (or nil, if not needed).
- zip android.WritablePath
-
- // Rules which should be used in make to install the outputs.
- profileInstalls android.RuleBuilderInstalls
-
- // Path to the license metadata file for the module that built the profile.
- profileLicenseMetadataFile android.OptionalPath
-
- // Path to the image profile file on host (or empty, if profile is not generated).
- profilePathOnHost android.Path
-
- // Target-dependent fields.
- variants []*bootImageVariant
-
- // Path of the preloaded classes file.
- preloadedClassesFile string
-}
-
-// Target-dependent description of a boot image.
-type bootImageVariant struct {
- *bootImageConfig
-
- // Target for which the image is generated.
- target android.Target
-
- // The "locations" of jars.
- dexLocations []string // for this image
- dexLocationsDeps []string // for the dependency images and in this image
-
- // Paths to image files.
- imagePathOnHost android.OutputPath // first image file path on host
- imagePathOnDevice string // first image file path on device
-
- // All the files that constitute this image variant, i.e. .art, .oat and .vdex files.
- imagesDeps android.OutputPaths
-
- // The path to the primary image variant's imagePathOnHost field, where primary image variant
- // means the image variant that this extends.
- //
- // This is only set for a variant of an image that extends another image.
- primaryImages android.OutputPath
-
- // The paths to the primary image variant's imagesDeps field, where primary image variant
- // means the image variant that this extends.
- //
- // This is only set for a variant of an image that extends another image.
- primaryImagesDeps android.Paths
-
- // Rules which should be used in make to install the outputs on host.
- installs android.RuleBuilderInstalls
- vdexInstalls android.RuleBuilderInstalls
- unstrippedInstalls android.RuleBuilderInstalls
-
- // Rules which should be used in make to install the outputs on device.
- deviceInstalls android.RuleBuilderInstalls
-
- // Path to the license metadata file for the module that built the image.
- licenseMetadataFile android.OptionalPath
-}
-
-// Get target-specific boot image variant for the given boot image config and target.
-func (image bootImageConfig) getVariant(target android.Target) *bootImageVariant {
- for _, variant := range image.variants {
- if variant.target.Os == target.Os && variant.target.Arch.ArchType == target.Arch.ArchType {
- return variant
- }
- }
- return nil
-}
-
-// Return any (the first) variant which is for the device (as opposed to for the host).
-func (image bootImageConfig) getAnyAndroidVariant() *bootImageVariant {
- for _, variant := range image.variants {
- if variant.target.Os == android.Android {
- return variant
- }
- }
- return nil
-}
-
-// Return the name of a boot image module given a boot image config and a component (module) index.
-// A module name is a combination of the Java library name, and the boot image stem (that is stored
-// in the config).
-func (image bootImageConfig) moduleName(ctx android.PathContext, idx int) string {
- // The first module of the primary boot image is special: its module name has only the stem, but
- // not the library name. All other module names are of the form <stem>-<library name>
- m := image.modules.Jar(idx)
- name := image.stem
- if idx != 0 || image.extends != nil {
- name += "-" + android.ModuleStem(m)
- }
- return name
-}
-
-// Return the name of the first boot image module, or stem if the list of modules is empty.
-func (image bootImageConfig) firstModuleNameOrStem(ctx android.PathContext) string {
- if image.modules.Len() > 0 {
- return image.moduleName(ctx, 0)
- } else {
- return image.stem
- }
-}
-
-// Return filenames for the given boot image component, given the output directory and a list of
-// extensions.
-func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) android.OutputPaths {
- ret := make(android.OutputPaths, 0, image.modules.Len()*len(exts))
- for i := 0; i < image.modules.Len(); i++ {
- name := image.moduleName(ctx, i)
- for _, ext := range exts {
- ret = append(ret, dir.Join(ctx, name+ext))
- }
- }
- return ret
-}
-
-// apexVariants returns a list of all *bootImageVariant that could be included in an apex.
-func (image *bootImageConfig) apexVariants() []*bootImageVariant {
- variants := []*bootImageVariant{}
- for _, variant := range image.variants {
- // We also generate boot images for host (for testing), but we don't need those in the apex.
- // TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device
- if variant.target.Os == android.Android {
- variants = append(variants, variant)
- }
- }
- return variants
-}
-
-// Returns true if the boot image should be installed in the APEX.
-func (image *bootImageConfig) shouldInstallInApex() bool {
- return strings.HasPrefix(image.installDirOnDevice, "apex/")
-}
-
-// Return boot image locations (as a list of symbolic paths).
-//
-// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really
-// exist on the device. Typically it is /apex/com.android.art/javalib/boot.art and should be the
-// same for all supported architectures on the device. The concrete architecture specific files
-// actually end up in architecture-specific sub-directory such as arm, arm64, x86, or x86_64.
-//
-// For example a physical file /apex/com.android.art/javalib/x86/boot.art has "image location"
-// /apex/com.android.art/javalib/boot.art (which is not an actual file).
-//
-// For a primary boot image the list of locations has a single element.
-//
-// For a boot image extension the list of locations contains a location for all dependency images
-// (including the primary image) and the location of the extension itself. For example, for the
-// Framework boot image extension that depends on the primary ART boot image the list contains two
-// elements.
-//
-// The location is passed as an argument to the ART tools like dex2oat instead of the real path.
-// ART tools will then reconstruct the architecture-specific real path.
-//
-func (image *bootImageVariant) imageLocations() (imageLocationsOnHost []string, imageLocationsOnDevice []string) {
- if image.extends != nil {
- imageLocationsOnHost, imageLocationsOnDevice = image.extends.getVariant(image.target).imageLocations()
- }
- return append(imageLocationsOnHost, dexpreopt.PathToLocation(image.imagePathOnHost, image.target.Arch.ArchType)),
- append(imageLocationsOnDevice, dexpreopt.PathStringToLocation(image.imagePathOnDevice, image.target.Arch.ArchType))
-}
-
-func dexpreoptBootJarsFactory() android.SingletonModule {
- m := &dexpreoptBootJars{}
- android.InitAndroidModule(m)
- return m
-}
-
-func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
- ctx.RegisterSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory)
-}
-
-func SkipDexpreoptBootJars(ctx android.PathContext) bool {
- return dexpreopt.GetGlobalConfig(ctx).DisablePreoptBootImages
-}
-
-// Singleton module for generating boot image build rules.
-type dexpreoptBootJars struct {
- android.SingletonModuleBase
-
- // Default boot image config (currently always the Framework boot image extension). It should be
- // noted that JIT-Zygote builds use ART APEX image instead of the Framework boot image extension,
- // but the switch is handled not here, but in the makefiles (triggered with
- // DEXPREOPT_USE_ART_IMAGE=true).
- defaultBootImage *bootImageConfig
-
- // Build path to a config file that Soong writes for Make (to be used in makefiles that install
- // the default boot image).
- dexpreoptConfigForMake android.WritablePath
-}
-
-// Provide paths to boot images for use by modules that depend upon them.
-//
-// The build rules are created in GenerateSingletonBuildActions().
-func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- // Placeholder for now.
-}
-
-// Generate build rules for boot images.
-func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonContext) {
- if SkipDexpreoptBootJars(ctx) {
- return
- }
- if dexpreopt.GetCachedGlobalSoongConfig(ctx) == nil {
- // No module has enabled dexpreopting, so we assume there will be no boot image to make.
- return
- }
-
- d.dexpreoptConfigForMake = android.PathForOutput(ctx, ctx.Config().DeviceName(), "dexpreopt.config")
- writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
-
- global := dexpreopt.GetGlobalConfig(ctx)
- if !shouldBuildBootImages(ctx.Config(), global) {
- return
- }
-
- defaultImageConfig := defaultBootImageConfig(ctx)
- d.defaultBootImage = defaultImageConfig
-}
-
-// shouldBuildBootImages determines whether boot images should be built.
-func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig) bool {
- // Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
- // and invalidate first-stage artifacts which are crucial to SANITIZE_LITE builds.
- // Note: this is technically incorrect. Compiled code contains stack checks which may depend
- // on ASAN settings.
- if len(config.SanitizeDevice()) == 1 && config.SanitizeDevice()[0] == "address" && global.SanitizeLite {
- return false
- }
- return true
-}
-
-// copyBootJarsToPredefinedLocations generates commands that will copy boot jars to predefined
-// paths in the global config.
-func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJarsByModule bootDexJarByModule, dstBootJarsByModule map[string]android.WritablePath) {
- // Create the super set of module names.
- names := []string{}
- names = append(names, android.SortedStringKeys(srcBootDexJarsByModule)...)
- names = append(names, android.SortedStringKeys(dstBootJarsByModule)...)
- names = android.SortedUniqueStrings(names)
- for _, name := range names {
- src := srcBootDexJarsByModule[name]
- dst := dstBootJarsByModule[name]
-
- if src == nil {
- // A dex boot jar should be provided by the source java module. It needs to be installable or
- // have compile_dex=true - cf. assignments to java.Module.dexJarFile.
- //
- // However, the source java module may be either replaced or overridden (using prefer:true) by
- // a prebuilt java module with the same name. In that case the dex boot jar needs to be
- // provided by the corresponding prebuilt APEX module. That APEX is the one that refers
- // through a exported_(boot|systemserver)classpath_fragments property to a
- // prebuilt_(boot|systemserver)classpath_fragment module, which in turn lists the prebuilt
- // java module in the contents property. If that chain is broken then this dependency will
- // fail.
- if !ctx.Config().AllowMissingDependencies() {
- ctx.ModuleErrorf("module %s does not provide a dex boot jar (see comment next to this message in Soong for details)", name)
- } else {
- ctx.AddMissingDependencies([]string{name})
- }
- } else if dst == nil {
- ctx.ModuleErrorf("module %s is not part of the boot configuration", name)
- } else {
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Input: src,
- Output: dst,
- })
- }
- }
-}
-
-// buildBootImageVariantsForAndroidOs generates rules to build the boot image variants for the
-// android.Android OsType and returns a map from the architectures to the paths of the generated
-// boot image files.
-//
-// The paths are returned because they are needed elsewhere in Soong, e.g. for populating an APEX.
-func buildBootImageVariantsForAndroidOs(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath) bootImageFilesByArch {
- return buildBootImageForOsType(ctx, image, profile, android.Android)
-}
-
-// buildBootImageVariantsForBuildOs generates rules to build the boot image variants for the
-// config.BuildOS OsType, i.e. the type of OS on which the build is being running.
-//
-// The files need to be generated into their predefined location because they are used from there
-// both within Soong and outside, e.g. for ART based host side testing and also for use by some
-// cloud based tools. However, they are not needed by callers of this function and so the paths do
-// not need to be returned from this func, unlike the buildBootImageVariantsForAndroidOs func.
-func buildBootImageVariantsForBuildOs(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath) {
- buildBootImageForOsType(ctx, image, profile, ctx.Config().BuildOS)
-}
-
-// buildBootImageForOsType takes a bootImageConfig, a profile file and an android.OsType
-// boot image files are required for and it creates rules to build the boot image
-// files for all the required architectures for them.
-//
-// It returns a map from android.ArchType to the predefined paths of the boot image files.
-func buildBootImageForOsType(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath, requiredOsType android.OsType) bootImageFilesByArch {
- filesByArch := bootImageFilesByArch{}
- for _, variant := range image.variants {
- if variant.target.Os == requiredOsType {
- buildBootImageVariant(ctx, variant, profile)
- filesByArch[variant.target.Arch.ArchType] = variant.imagesDeps.Paths()
- }
- }
-
- return filesByArch
-}
-
-// buildBootImageZipInPredefinedLocation generates a zip file containing all the boot image files.
-//
-// The supplied filesByArch is nil when the boot image files have not been generated. Otherwise, it
-// is a map from android.ArchType to the predefined locations.
-func buildBootImageZipInPredefinedLocation(ctx android.ModuleContext, image *bootImageConfig, filesByArch bootImageFilesByArch) {
- if filesByArch == nil {
- return
- }
-
- // Compute the list of files from all the architectures.
- zipFiles := android.Paths{}
- for _, archType := range android.ArchTypeList() {
- zipFiles = append(zipFiles, filesByArch[archType]...)
- }
-
- rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
- BuiltTool("soong_zip").
- FlagWithOutput("-o ", image.zip).
- FlagWithArg("-C ", image.dir.Join(ctx, android.Android.String()).String()).
- FlagWithInputList("-f ", zipFiles, " -f ")
-
- rule.Build("zip_"+image.name, "zip "+image.name+" image")
-}
-
-// Generate boot image build rules for a specific target.
-func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, profile android.Path) {
-
- globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
- global := dexpreopt.GetGlobalConfig(ctx)
-
- arch := image.target.Arch.ArchType
- os := image.target.Os.String() // We need to distinguish host-x86 and device-x86.
- symbolsDir := image.symbolsDir.Join(ctx, os, image.installDirOnHost, arch.String())
- symbolsFile := symbolsDir.Join(ctx, image.stem+".oat")
- outputDir := image.dir.Join(ctx, os, image.installDirOnHost, arch.String())
- outputPath := outputDir.Join(ctx, image.stem+".oat")
- oatLocation := dexpreopt.PathToLocation(outputPath, arch)
- imagePath := outputPath.ReplaceExtension(ctx, "art")
-
- rule := android.NewRuleBuilder(pctx, ctx)
-
- rule.Command().Text("mkdir").Flag("-p").Flag(symbolsDir.String())
- rule.Command().Text("rm").Flag("-f").
- Flag(symbolsDir.Join(ctx, "*.art").String()).
- Flag(symbolsDir.Join(ctx, "*.oat").String()).
- Flag(symbolsDir.Join(ctx, "*.invocation").String())
- rule.Command().Text("rm").Flag("-f").
- Flag(outputDir.Join(ctx, "*.art").String()).
- Flag(outputDir.Join(ctx, "*.oat").String()).
- Flag(outputDir.Join(ctx, "*.invocation").String())
-
- cmd := rule.Command()
-
- extraFlags := ctx.Config().Getenv("ART_BOOT_IMAGE_EXTRA_ARGS")
- if extraFlags == "" {
- // Use ANDROID_LOG_TAGS to suppress most logging by default...
- cmd.Text(`ANDROID_LOG_TAGS="*:e"`)
- } else {
- // ...unless the boot image is generated specifically for testing, then allow all logging.
- cmd.Text(`ANDROID_LOG_TAGS="*:v"`)
- }
-
- invocationPath := outputPath.ReplaceExtension(ctx, "invocation")
-
- cmd.Tool(globalSoong.Dex2oat).
- Flag("--avoid-storing-invocation").
- FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath).
- Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatImageXms).
- Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatImageXmx)
-
- if profile != nil {
- cmd.FlagWithInput("--profile-file=", profile)
- }
-
- dirtyImageFile := "frameworks/base/config/dirty-image-objects"
- dirtyImagePath := android.ExistentPathForSource(ctx, dirtyImageFile)
- if dirtyImagePath.Valid() {
- cmd.FlagWithInput("--dirty-image-objects=", dirtyImagePath.Path())
- }
-
- if image.extends != nil {
- // It is a boot image extension, so it needs the boot image it depends on (in this case the
- // primary ART APEX image).
- artImage := image.primaryImages
- cmd.
- Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
- Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", image.dexLocationsDeps, ":").
- // Add the path to the first file in the boot image with the arch specific directory removed,
- // dex2oat will reconstruct the path to the actual file when it needs it. As the actual path
- // to the file cannot be passed to the command make sure to add the actual path as an Implicit
- // dependency to ensure that it is built before the command runs.
- FlagWithArg("--boot-image=", dexpreopt.PathToLocation(artImage, arch)).Implicit(artImage).
- // Similarly, the dex2oat tool will automatically find the paths to other files in the base
- // boot image so make sure to add them as implicit dependencies to ensure that they are built
- // before this command is run.
- Implicits(image.primaryImagesDeps)
- } else {
- // It is a primary image, so it needs a base address.
- cmd.FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress())
- }
-
- // We always expect a preloaded classes file to be available. However, if we cannot find it, it's
- // OK to not pass the flag to dex2oat.
- preloadedClassesPath := android.ExistentPathForSource(ctx, image.preloadedClassesFile)
- if preloadedClassesPath.Valid() {
- cmd.FlagWithInput("--preloaded-classes=", preloadedClassesPath.Path())
- }
-
- cmd.
- FlagForEachInput("--dex-file=", image.dexPaths.Paths()).
- FlagForEachArg("--dex-location=", image.dexLocations).
- Flag("--generate-debug-info").
- Flag("--generate-build-id").
- Flag("--image-format=lz4hc").
- FlagWithArg("--oat-symbols=", symbolsFile.String()).
- Flag("--strip").
- FlagWithArg("--oat-file=", outputPath.String()).
- FlagWithArg("--oat-location=", oatLocation).
- FlagWithArg("--image=", imagePath.String()).
- FlagWithArg("--instruction-set=", arch.String()).
- FlagWithArg("--android-root=", global.EmptyDirectory).
- FlagWithArg("--no-inline-from=", "core-oj.jar").
- Flag("--force-determinism").
- Flag("--abort-on-hard-verifier-error")
-
- // Use the default variant/features for host builds.
- // The map below contains only device CPU info (which might be x86 on some devices).
- if image.target.Os == android.Android {
- cmd.FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch])
- cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
- }
-
- if global.BootFlags != "" {
- cmd.Flag(global.BootFlags)
- }
-
- if extraFlags != "" {
- cmd.Flag(extraFlags)
- }
-
- cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape(failureMessage))
-
- installDir := filepath.Join("/", image.installDirOnHost, arch.String())
-
- var vdexInstalls android.RuleBuilderInstalls
- var unstrippedInstalls android.RuleBuilderInstalls
- var deviceInstalls android.RuleBuilderInstalls
-
- for _, artOrOat := range image.moduleFiles(ctx, outputDir, ".art", ".oat") {
- cmd.ImplicitOutput(artOrOat)
-
- // Install the .oat and .art files
- rule.Install(artOrOat, filepath.Join(installDir, artOrOat.Base()))
- }
-
- for _, vdex := range image.moduleFiles(ctx, outputDir, ".vdex") {
- cmd.ImplicitOutput(vdex)
-
- // Note that the vdex files are identical between architectures.
- // Make rules will create symlinks to share them between architectures.
- vdexInstalls = append(vdexInstalls,
- android.RuleBuilderInstall{vdex, filepath.Join(installDir, vdex.Base())})
- }
-
- for _, unstrippedOat := range image.moduleFiles(ctx, symbolsDir, ".oat") {
- cmd.ImplicitOutput(unstrippedOat)
-
- // Install the unstripped oat files. The Make rules will put these in $(TARGET_OUT_UNSTRIPPED)
- unstrippedInstalls = append(unstrippedInstalls,
- android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())})
- }
-
- if image.installDirOnHost != image.installDirOnDevice && !image.shouldInstallInApex() && !ctx.Config().UnbundledBuild() {
- installDirOnDevice := filepath.Join("/", image.installDirOnDevice, arch.String())
- for _, file := range image.moduleFiles(ctx, outputDir, ".art", ".oat", ".vdex") {
- deviceInstalls = append(deviceInstalls,
- android.RuleBuilderInstall{file, filepath.Join(installDirOnDevice, file.Base())})
- }
- }
-
- rule.Build(image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String())
-
- // save output and installed files for makevars
- image.installs = rule.Installs()
- image.vdexInstalls = vdexInstalls
- image.unstrippedInstalls = unstrippedInstalls
- image.deviceInstalls = deviceInstalls
- image.licenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
-}
-
-const failureMessage = `ERROR: Dex2oat failed to compile a boot image.
-It is likely that the boot classpath is inconsistent.
-Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.`
-
-func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath {
- globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
- global := dexpreopt.GetGlobalConfig(ctx)
-
- if global.DisableGenerateProfile {
- return nil
- }
-
- defaultProfile := "frameworks/base/config/boot-image-profile.txt"
-
- rule := android.NewRuleBuilder(pctx, ctx)
-
- var bootImageProfile android.Path
- if len(global.BootImageProfiles) > 1 {
- combinedBootImageProfile := image.dir.Join(ctx, "boot-image-profile.txt")
- rule.Command().Text("cat").Inputs(global.BootImageProfiles).Text(">").Output(combinedBootImageProfile)
- bootImageProfile = combinedBootImageProfile
- } else if len(global.BootImageProfiles) == 1 {
- bootImageProfile = global.BootImageProfiles[0]
- } else if path := android.ExistentPathForSource(ctx, defaultProfile); path.Valid() {
- bootImageProfile = path.Path()
- } else {
- // No profile (not even a default one, which is the case on some branches
- // like master-art-host that don't have frameworks/base).
- // Return nil and continue without profile.
- return nil
- }
-
- profile := image.dir.Join(ctx, "boot.prof")
-
- rule.Command().
- Text(`ANDROID_LOG_TAGS="*:e"`).
- Tool(globalSoong.Profman).
- Flag("--output-profile-type=boot").
- FlagWithInput("--create-profile-from=", bootImageProfile).
- FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
- FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
- FlagWithOutput("--reference-profile-file=", profile)
-
- if image == defaultBootImageConfig(ctx) {
- rule.Install(profile, "/system/etc/boot-image.prof")
- image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
- image.profileLicenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
- }
-
- rule.Build("bootJarsProfile", "profile boot jars")
-
- image.profilePathOnHost = profile
-
- return profile
-}
-
-// bootFrameworkProfileRule generates the rule to create the boot framework profile and
-// returns a path to the generated file.
-func bootFrameworkProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath {
- globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
- global := dexpreopt.GetGlobalConfig(ctx)
-
- if global.DisableGenerateProfile || ctx.Config().UnbundledBuild() {
- return nil
- }
-
- defaultProfile := "frameworks/base/config/boot-profile.txt"
- bootFrameworkProfile := android.PathForSource(ctx, defaultProfile)
-
- profile := image.dir.Join(ctx, "boot.bprof")
-
- rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
- Text(`ANDROID_LOG_TAGS="*:e"`).
- Tool(globalSoong.Profman).
- Flag("--output-profile-type=bprof").
- FlagWithInput("--create-profile-from=", bootFrameworkProfile).
- FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
- FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
- FlagWithOutput("--reference-profile-file=", profile)
-
- rule.Install(profile, "/system/etc/boot-image.bprof")
- rule.Build("bootFrameworkProfile", "profile boot framework jars")
- image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
- image.profileLicenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
-
- return profile
-}
-
-func dumpOatRules(ctx android.ModuleContext, image *bootImageConfig) {
- var allPhonies android.Paths
- for _, image := range image.variants {
- arch := image.target.Arch.ArchType
- suffix := arch.String()
- // Host and target might both use x86 arch. We need to ensure the names are unique.
- if image.target.Os.Class == android.Host {
- suffix = "host-" + suffix
- }
- // Create a rule to call oatdump.
- output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt")
- rule := android.NewRuleBuilder(pctx, ctx)
- imageLocationsOnHost, _ := image.imageLocations()
- rule.Command().
- BuiltTool("oatdump").
- FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
- FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
- FlagWithArg("--image=", strings.Join(imageLocationsOnHost, ":")).Implicits(image.imagesDeps.Paths()).
- FlagWithOutput("--output=", output).
- FlagWithArg("--instruction-set=", arch.String())
- rule.Build("dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
-
- // Create a phony rule that depends on the output file and prints the path.
- phony := android.PathForPhony(ctx, "dump-oat-boot-"+suffix)
- rule = android.NewRuleBuilder(pctx, ctx)
- rule.Command().
- Implicit(output).
- ImplicitOutput(phony).
- Text("echo").FlagWithArg("Output in ", output.String())
- rule.Build("phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
-
- allPhonies = append(allPhonies, phony)
- }
-
- phony := android.PathForPhony(ctx, "dump-oat-boot")
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Phony,
- Output: phony,
- Inputs: allPhonies,
- Description: "dump-oat-boot",
- })
-}
-
-func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) {
- data := dexpreopt.GetGlobalConfigRawData(ctx)
-
- android.WriteFileRule(ctx, path, string(data))
-}
-
-// Define Make variables for boot image names, paths, etc. These variables are used in makefiles
-// (make/core/dex_preopt_libart.mk) to generate install rules that copy boot image files to the
-// correct output directories.
-func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
- if d.dexpreoptConfigForMake != nil {
- ctx.Strict("DEX_PREOPT_CONFIG_FOR_MAKE", d.dexpreoptConfigForMake.String())
- ctx.Strict("DEX_PREOPT_SOONG_CONFIG_FOR_MAKE", android.PathForOutput(ctx, "dexpreopt_soong.config").String())
- }
-
- image := d.defaultBootImage
- if image == nil {
- return
- }
-
- ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
- if image.profileLicenseMetadataFile.Valid() {
- ctx.Strict("DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA", image.profileLicenseMetadataFile.String())
- }
-
- global := dexpreopt.GetGlobalConfig(ctx)
- dexPaths, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
- ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(dexPaths.Strings(), " "))
- ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(dexLocations, " "))
-
- for _, variant := range image.variants {
- suffix := ""
- if variant.target.Os.Class == android.Host {
- suffix = "_host"
- }
- sfx := suffix + "_" + variant.target.Arch.ArchType.String()
- ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, variant.vdexInstalls.String())
- ctx.Strict("DEXPREOPT_IMAGE_"+sfx, variant.imagePathOnHost.String())
- ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(variant.imagesDeps.Strings(), " "))
- ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, variant.installs.String())
- ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, variant.unstrippedInstalls.String())
- if variant.licenseMetadataFile.Valid() {
- ctx.Strict("DEXPREOPT_IMAGE_LICENSE_METADATA_"+sfx, variant.licenseMetadataFile.String())
- }
- }
- imageLocationsOnHost, imageLocationsOnDevice := image.getAnyAndroidVariant().imageLocations()
- ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_ON_HOST", strings.Join(imageLocationsOnHost, ":"))
- ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICE", strings.Join(imageLocationsOnDevice, ":"))
- ctx.Strict("DEXPREOPT_IMAGE_ZIP", image.zip.String())
-
- // There used to be multiple images for JIT-Zygote mode, not there's only one.
- ctx.Strict("DEXPREOPT_IMAGE_NAMES", image.name)
-}
diff --git a/java/dexpreopt_config.go_v1 b/java/dexpreopt_config.go_v1
deleted file mode 100644
index d71e2bb..0000000
--- a/java/dexpreopt_config.go_v1
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright 2019 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 java
-
-import (
- "path/filepath"
- "strings"
-
- "android/soong/android"
- "android/soong/dexpreopt"
-)
-
-// dexpreoptTargets returns the list of targets that are relevant to dexpreopting, which excludes architectures
-// supported through native bridge.
-func dexpreoptTargets(ctx android.PathContext) []android.Target {
- var targets []android.Target
- for _, target := range ctx.Config().Targets[android.Android] {
- if target.NativeBridge == android.NativeBridgeDisabled {
- targets = append(targets, target)
- }
- }
- // We may also need the images on host in order to run host-based tests.
- for _, target := range ctx.Config().Targets[ctx.Config().BuildOS] {
- targets = append(targets, target)
- }
-
- return targets
-}
-
-var (
- bootImageConfigKey = android.NewOnceKey("bootImageConfig")
- bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw")
- artBootImageName = "art"
- frameworkBootImageName = "boot"
-)
-
-func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig {
- return ctx.Config().Once(bootImageConfigRawKey, func() interface{} {
- global := dexpreopt.GetGlobalConfig(ctx)
-
- artModules := global.ArtApexJars
- frameworkModules := global.BootJars.RemoveList(artModules)
-
- // ART config for the primary boot image in the ART apex.
- // It includes the Core Libraries.
- artCfg := bootImageConfig{
- name: artBootImageName,
- stem: "boot",
- installDirOnHost: "apex/art_boot_images/javalib",
- installDirOnDevice: "system/framework",
- profileInstallPathInApex: "etc/boot-image.prof",
- modules: artModules,
- preloadedClassesFile: "art/build/boot/preloaded-classes",
- }
-
- // Framework config for the boot image extension.
- // It includes framework libraries and depends on the ART config.
- frameworkSubdir := "system/framework"
- frameworkCfg := bootImageConfig{
- extends: &artCfg,
- name: frameworkBootImageName,
- stem: "boot",
- installDirOnHost: frameworkSubdir,
- installDirOnDevice: frameworkSubdir,
- modules: frameworkModules,
- preloadedClassesFile: "frameworks/base/config/preloaded-classes",
- }
-
- return map[string]*bootImageConfig{
- artBootImageName: &artCfg,
- frameworkBootImageName: &frameworkCfg,
- }
- }).(map[string]*bootImageConfig)
-}
-
-// Construct the global boot image configs.
-func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
- return ctx.Config().Once(bootImageConfigKey, func() interface{} {
- targets := dexpreoptTargets(ctx)
- deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
-
- configs := genBootImageConfigRaw(ctx)
- artCfg := configs[artBootImageName]
- frameworkCfg := configs[frameworkBootImageName]
-
- // common to all configs
- for _, c := range configs {
- c.dir = deviceDir.Join(ctx, "dex_"+c.name+"jars")
- c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
-
- // expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
- imageName := c.firstModuleNameOrStem(ctx) + ".art"
-
- // The path to bootclasspath dex files needs to be known at module
- // GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
- // Set up known paths for them, the singleton rules will copy them there.
- // TODO(b/143682396): use module dependencies instead
- inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
- c.dexPaths = c.modules.BuildPaths(ctx, inputDir)
- c.dexPathsByModule = c.modules.BuildPathsByModule(ctx, inputDir)
- c.dexPathsDeps = c.dexPaths
-
- // Create target-specific variants.
- for _, target := range targets {
- arch := target.Arch.ArchType
- imageDir := c.dir.Join(ctx, target.Os.String(), c.installDirOnHost, arch.String())
- variant := &bootImageVariant{
- bootImageConfig: c,
- target: target,
- imagePathOnHost: imageDir.Join(ctx, imageName),
- imagePathOnDevice: filepath.Join("/", c.installDirOnDevice, arch.String(), imageName),
- imagesDeps: c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"),
- dexLocations: c.modules.DevicePaths(ctx.Config(), target.Os),
- }
- variant.dexLocationsDeps = variant.dexLocations
- c.variants = append(c.variants, variant)
- }
-
- c.zip = c.dir.Join(ctx, c.name+".zip")
- }
-
- // specific to the framework config
- frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
- for i := range targets {
- frameworkCfg.variants[i].primaryImages = artCfg.variants[i].imagePathOnHost
- frameworkCfg.variants[i].primaryImagesDeps = artCfg.variants[i].imagesDeps.Paths()
- frameworkCfg.variants[i].dexLocationsDeps = append(artCfg.variants[i].dexLocations, frameworkCfg.variants[i].dexLocationsDeps...)
- }
-
- return configs
- }).(map[string]*bootImageConfig)
-}
-
-func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig {
- return genBootImageConfigs(ctx)[frameworkBootImageName]
-}
-
-// Apex boot config allows to access build/install paths of apex boot jars without going
-// through the usual trouble of registering dependencies on those modules and extracting build paths
-// from those dependencies.
-type apexBootConfig struct {
- // A list of apex boot jars.
- modules android.ConfiguredJarList
-
- // A list of predefined build paths to apex boot jars. They are configured very early,
- // before the modules for these jars are processed and the actual paths are generated, and
- // later on a singleton adds commands to copy actual jars to the predefined paths.
- dexPaths android.WritablePaths
-
- // Map from module name (without prebuilt_ prefix) to the predefined build path.
- dexPathsByModule map[string]android.WritablePath
-
- // A list of dex locations (a.k.a. on-device paths) to the boot jars.
- dexLocations []string
-}
-
-var updatableBootConfigKey = android.NewOnceKey("apexBootConfig")
-
-// Returns apex boot config.
-func GetApexBootConfig(ctx android.PathContext) apexBootConfig {
- return ctx.Config().Once(updatableBootConfigKey, func() interface{} {
- apexBootJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
-
- dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "apex_bootjars")
- dexPaths := apexBootJars.BuildPaths(ctx, dir)
- dexPathsByModuleName := apexBootJars.BuildPathsByModule(ctx, dir)
-
- dexLocations := apexBootJars.DevicePaths(ctx.Config(), android.Android)
-
- return apexBootConfig{apexBootJars, dexPaths, dexPathsByModuleName, dexLocations}
- }).(apexBootConfig)
-}
-
-// Returns a list of paths and a list of locations for the boot jars used in dexpreopt (to be
-// passed in -Xbootclasspath and -Xbootclasspath-locations arguments for dex2oat).
-func bcpForDexpreopt(ctx android.PathContext, withUpdatable bool) (android.WritablePaths, []string) {
- // Non-updatable boot jars (they are used both in the boot image and in dexpreopt).
- bootImage := defaultBootImageConfig(ctx)
- dexPaths := bootImage.dexPathsDeps
- // The dex locations for all Android variants are identical.
- dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps
-
- if withUpdatable {
- // Apex boot jars (they are used only in dexpreopt, but not in the boot image).
- apexBootConfig := GetApexBootConfig(ctx)
- dexPaths = append(dexPaths, apexBootConfig.dexPaths...)
- dexLocations = append(dexLocations, apexBootConfig.dexLocations...)
- }
-
- return dexPaths, dexLocations
-}
-
-var defaultBootclasspathKey = android.NewOnceKey("defaultBootclasspath")
-
-var copyOf = android.CopyOf
-
-func init() {
- android.RegisterMakeVarsProvider(pctx, dexpreoptConfigMakevars)
-}
-
-func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
- ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":"))
-}
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 023d619..9663922 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -256,6 +256,10 @@
return j.SdkVersion(ctx)
}
+func (j *Javadoc) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.SdkSpec {
+ return j.SdkVersion(ctx)
+}
+
func (j *Javadoc) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
return j.SdkVersion(ctx)
}
diff --git a/java/fuzz.go b/java/fuzz.go
index b306991..d0f369f 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -171,6 +171,10 @@
return
}
+ if javaFuzzModule.Target().HostCross {
+ return
+ }
+
fuzzModuleValidator := fuzz.FuzzModule{
javaFuzzModule.ModuleBase,
javaFuzzModule.DefaultableModuleBase,
diff --git a/java/java.go b/java/java.go
index 0dfb968..77ab402 100644
--- a/java/java.go
+++ b/java/java.go
@@ -24,6 +24,7 @@
"strings"
"android/soong/bazel"
+ "android/soong/bazel/cquery"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -118,6 +119,16 @@
copyEverythingToSnapshot,
}
+ snapshotRequiresImplementationJar = func(ctx android.SdkMemberContext) bool {
+ // In the S build the build will break if updatable-media does not provide a full implementation
+ // jar. That issue was fixed in Tiramisu by b/229932396.
+ if ctx.IsTargetBuildBeforeTiramisu() && ctx.Name() == "updatable-media" {
+ return true
+ }
+
+ return false
+ }
+
// Supports adding java boot libraries to module_exports and sdk.
//
// The build has some implicit dependencies (via the boot jars configuration) on a number of
@@ -135,13 +146,21 @@
SupportsSdk: true,
},
func(ctx android.SdkMemberContext, j *Library) android.Path {
+ if snapshotRequiresImplementationJar(ctx) {
+ return exportImplementationClassesJar(ctx, j)
+ }
+
// Java boot libs are only provided in the SDK to provide access to their dex implementation
// jar for use by dexpreopting and boot jars package check. They do not need to provide an
// actual implementation jar but the java_import will need a file that exists so just copy an
// empty file. Any attempt to use that file as a jar will cause a build error.
return ctx.SnapshotBuilder().EmptyFile()
},
- func(osPrefix, name string) string {
+ func(ctx android.SdkMemberContext, osPrefix, name string) string {
+ if snapshotRequiresImplementationJar(ctx) {
+ return sdkSnapshotFilePathForJar(ctx, osPrefix, name)
+ }
+
// Create a special name for the implementation jar to try and provide some useful information
// to a developer that attempts to compile against this.
// TODO(b/175714559): Provide a proper error message in Soong not ninja.
@@ -164,6 +183,9 @@
android.SdkMemberTypeBase{
PropertyName: "java_systemserver_libs",
SupportsSdk: true,
+
+ // This was only added in Tiramisu.
+ SupportedBuildReleaseSpecification: "Tiramisu+",
},
func(ctx android.SdkMemberContext, j *Library) android.Path {
// Java systemserver libs are only provided in the SDK to provide access to their dex
@@ -172,7 +194,7 @@
// file. Any attempt to use that file as a jar will cause a build error.
return ctx.SnapshotBuilder().EmptyFile()
},
- func(osPrefix, name string) string {
+ func(_ android.SdkMemberContext, osPrefix, name string) string {
// Create a special name for the implementation jar to try and provide some useful information
// to a developer that attempts to compile against this.
// TODO(b/175714559): Provide a proper error message in Soong not ninja.
@@ -510,6 +532,20 @@
}
}
+func (v javaVersion) StringForKotlinc() string {
+ // $ ./external/kotlinc/bin/kotlinc -jvm-target foo
+ // error: unknown JVM target version: foo
+ // Supported versions: 1.6, 1.8, 9, 10, 11, 12, 13, 14, 15, 16, 17
+ switch v {
+ case JAVA_VERSION_7:
+ return "1.6"
+ case JAVA_VERSION_9:
+ return "9"
+ default:
+ return v.String()
+ }
+}
+
// Returns true if javac targeting this version uses system modules instead of a bootclasspath.
func (v javaVersion) usesJavaModules() bool {
return v >= 9
@@ -528,7 +564,7 @@
case "11":
return JAVA_VERSION_11
case "17":
- return JAVA_VERSION_11
+ return JAVA_VERSION_17
case "10", "12", "13", "14", "15", "16":
ctx.PropertyErrorf("java_version", "Java language level %s is not supported", javaVersion)
return JAVA_VERSION_UNSUPPORTED
@@ -655,7 +691,7 @@
)
// path to the jar file of a java library. Relative to <sdk_root>/<api_dir>
-func sdkSnapshotFilePathForJar(osPrefix, name string) string {
+func sdkSnapshotFilePathForJar(_ android.SdkMemberContext, osPrefix, name string) string {
return sdkSnapshotFilePathForMember(osPrefix, name, jarFileSuffix)
}
@@ -672,7 +708,7 @@
// Function to compute the snapshot relative path to which the named library's
// jar should be copied.
- snapshotPathGetter func(osPrefix, name string) string
+ snapshotPathGetter func(ctx android.SdkMemberContext, osPrefix, name string) string
// True if only the jar should be copied to the snapshot, false if the jar plus any additional
// files like aidl files should also be copied.
@@ -730,7 +766,7 @@
exportedJar := p.JarToExport
if exportedJar != nil {
// Delegate the creation of the snapshot relative path to the member type.
- snapshotRelativeJavaLibPath := memberType.snapshotPathGetter(p.OsPrefix(), ctx.Name())
+ snapshotRelativeJavaLibPath := memberType.snapshotPathGetter(ctx, p.OsPrefix(), ctx.Name())
// Copy the exported jar to the snapshot.
builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
@@ -864,7 +900,25 @@
Data_native_bins []string `android:"arch_variant"`
// list of device binary modules that should be installed alongside the test
- Data_device_bins []string `android:"arch_variant"`
+ // This property only adds the first variant of the dependency
+ Data_device_bins_first []string `android:"arch_variant"`
+
+ // list of device binary modules that should be installed alongside the test
+ // This property adds 64bit AND 32bit variants of the dependency
+ Data_device_bins_both []string `android:"arch_variant"`
+
+ // list of device binary modules that should be installed alongside the test
+ // This property only adds 64bit variants of the dependency
+ Data_device_bins_64 []string `android:"arch_variant"`
+
+ // list of device binary modules that should be installed alongside the test
+ // This property adds 32bit variants of the dependency if available, or else
+ // defaults to the 64bit variant
+ Data_device_bins_prefer32 []string `android:"arch_variant"`
+
+ // list of device binary modules that should be installed alongside the test
+ // This property only adds 32bit variants of the dependency
+ Data_device_bins_32 []string `android:"arch_variant"`
}
type testHelperLibraryProperties struct {
@@ -931,6 +985,83 @@
return true
}
+func (j *TestHost) addDataDeviceBinsDeps(ctx android.BottomUpMutatorContext) {
+ if len(j.testHostProperties.Data_device_bins_first) > 0 {
+ deviceVariations := ctx.Config().AndroidFirstDeviceTarget.Variations()
+ ctx.AddFarVariationDependencies(deviceVariations, dataDeviceBinsTag, j.testHostProperties.Data_device_bins_first...)
+ }
+
+ var maybeAndroid32Target *android.Target
+ var maybeAndroid64Target *android.Target
+ android32TargetList := android.FirstTarget(ctx.Config().Targets[android.Android], "lib32")
+ android64TargetList := android.FirstTarget(ctx.Config().Targets[android.Android], "lib64")
+ if len(android32TargetList) > 0 {
+ maybeAndroid32Target = &android32TargetList[0]
+ }
+ if len(android64TargetList) > 0 {
+ maybeAndroid64Target = &android64TargetList[0]
+ }
+
+ if len(j.testHostProperties.Data_device_bins_both) > 0 {
+ if maybeAndroid32Target == nil && maybeAndroid64Target == nil {
+ ctx.PropertyErrorf("data_device_bins_both", "no device targets available. Targets: %q", ctx.Config().Targets)
+ return
+ }
+ if maybeAndroid32Target != nil {
+ ctx.AddFarVariationDependencies(
+ maybeAndroid32Target.Variations(),
+ dataDeviceBinsTag,
+ j.testHostProperties.Data_device_bins_both...,
+ )
+ }
+ if maybeAndroid64Target != nil {
+ ctx.AddFarVariationDependencies(
+ maybeAndroid64Target.Variations(),
+ dataDeviceBinsTag,
+ j.testHostProperties.Data_device_bins_both...,
+ )
+ }
+ }
+
+ if len(j.testHostProperties.Data_device_bins_prefer32) > 0 {
+ if maybeAndroid32Target != nil {
+ ctx.AddFarVariationDependencies(
+ maybeAndroid32Target.Variations(),
+ dataDeviceBinsTag,
+ j.testHostProperties.Data_device_bins_prefer32...,
+ )
+ } else {
+ if maybeAndroid64Target == nil {
+ ctx.PropertyErrorf("data_device_bins_prefer32", "no device targets available. Targets: %q", ctx.Config().Targets)
+ return
+ }
+ ctx.AddFarVariationDependencies(
+ maybeAndroid64Target.Variations(),
+ dataDeviceBinsTag,
+ j.testHostProperties.Data_device_bins_prefer32...,
+ )
+ }
+ }
+
+ if len(j.testHostProperties.Data_device_bins_32) > 0 {
+ if maybeAndroid32Target == nil {
+ ctx.PropertyErrorf("data_device_bins_32", "cannot find 32bit device target. Targets: %q", ctx.Config().Targets)
+ return
+ }
+ deviceVariations := maybeAndroid32Target.Variations()
+ ctx.AddFarVariationDependencies(deviceVariations, dataDeviceBinsTag, j.testHostProperties.Data_device_bins_32...)
+ }
+
+ if len(j.testHostProperties.Data_device_bins_64) > 0 {
+ if maybeAndroid64Target == nil {
+ ctx.PropertyErrorf("data_device_bins_64", "cannot find 64bit device target. Targets: %q", ctx.Config().Targets)
+ return
+ }
+ deviceVariations := maybeAndroid64Target.Variations()
+ ctx.AddFarVariationDependencies(deviceVariations, dataDeviceBinsTag, j.testHostProperties.Data_device_bins_64...)
+ }
+}
+
func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) {
if len(j.testHostProperties.Data_native_bins) > 0 {
for _, target := range ctx.MultiTargets() {
@@ -938,11 +1069,6 @@
}
}
- if len(j.testHostProperties.Data_device_bins) > 0 {
- deviceVariations := ctx.Config().AndroidFirstDeviceTarget.Variations()
- ctx.AddFarVariationDependencies(deviceVariations, dataDeviceBinsTag, j.testHostProperties.Data_device_bins...)
- }
-
if len(j.testProperties.Jni_libs) > 0 {
for _, target := range ctx.MultiTargets() {
sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
@@ -950,6 +1076,8 @@
}
}
+ j.addDataDeviceBinsDeps(ctx)
+
j.deps(ctx)
}
@@ -957,17 +1085,40 @@
j.extraResources = append(j.extraResources, p)
}
+func (j *TestHost) dataDeviceBins() []string {
+ ret := make([]string, 0,
+ len(j.testHostProperties.Data_device_bins_first)+
+ len(j.testHostProperties.Data_device_bins_both)+
+ len(j.testHostProperties.Data_device_bins_prefer32)+
+ len(j.testHostProperties.Data_device_bins_32)+
+ len(j.testHostProperties.Data_device_bins_64),
+ )
+
+ ret = append(ret, j.testHostProperties.Data_device_bins_first...)
+ ret = append(ret, j.testHostProperties.Data_device_bins_both...)
+ ret = append(ret, j.testHostProperties.Data_device_bins_prefer32...)
+ ret = append(ret, j.testHostProperties.Data_device_bins_32...)
+ ret = append(ret, j.testHostProperties.Data_device_bins_64...)
+
+ return ret
+}
+
func (j *TestHost) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var configs []tradefed.Config
- if len(j.testHostProperties.Data_device_bins) > 0 {
+ dataDeviceBins := j.dataDeviceBins()
+ if len(dataDeviceBins) > 0 {
// add Tradefed configuration to push device bins to device for testing
remoteDir := filepath.Join("/data/local/tests/unrestricted/", j.Name())
options := []tradefed.Option{{Name: "cleanup", Value: "true"}}
- for _, bin := range j.testHostProperties.Data_device_bins {
+ for _, bin := range dataDeviceBins {
fullPath := filepath.Join(remoteDir, bin)
options = append(options, tradefed.Option{Name: "push-file", Key: bin, Value: fullPath})
}
- configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.PushFilePreparer", options})
+ configs = append(configs, tradefed.Object{
+ Type: "target_preparer",
+ Class: "com.android.tradefed.targetprep.PushFilePreparer",
+ Options: options,
+ })
}
j.Test.generateAndroidBuildActionsWithConfig(ctx, configs)
@@ -1081,7 +1232,7 @@
exportedJar := p.JarToExport
if exportedJar != nil {
- snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
+ snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(ctx, p.OsPrefix(), ctx.Name())
builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
@@ -1111,7 +1262,7 @@
module.Module.properties.Installable = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
- module.Module.linter.test = true
+ module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
android.InitSdkAwareModule(module)
InitJavaModule(module, android.HostAndDeviceSupported)
@@ -1127,7 +1278,7 @@
module.Module.properties.Installable = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
- module.Module.linter.test = true
+ module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
InitJavaModule(module, android.HostAndDeviceSupported)
return module
@@ -1327,6 +1478,10 @@
// specified.
Min_sdk_version *string
+ // The max sdk version placeholder used to replace maxSdkVersion attributes on permission
+ // and uses-permission tags in manifest_fixer.
+ Replace_max_sdk_version_placeholder *string
+
Installable *bool
// If not empty, classes are restricted to the specified packages and their sub-packages.
@@ -1406,6 +1561,13 @@
return j.SdkVersion(ctx)
}
+func (j *Import) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.SdkSpec {
+ if j.properties.Replace_max_sdk_version_placeholder != nil {
+ return android.SdkSpecFrom(ctx, *j.properties.Replace_max_sdk_version_placeholder)
+ }
+ return android.SdkSpecFrom(ctx, "")
+}
+
func (j *Import) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
return j.SdkVersion(ctx)
}
@@ -1449,7 +1611,8 @@
}
}
-func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (j *Import) commonBuildActions(ctx android.ModuleContext) {
+ //TODO(b/231322772) these should come from Bazel once available
j.sdkVersion = j.SdkVersion(ctx)
j.minSdkVersion = j.MinSdkVersion(ctx)
@@ -1460,6 +1623,10 @@
if ctx.Windows() {
j.HideFromMake()
}
+}
+
+func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ j.commonBuildActions(ctx)
jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
@@ -1501,19 +1668,7 @@
addCLCFromDep(ctx, module, j.classLoaderContexts)
})
- if Bool(j.properties.Installable) {
- var installDir android.InstallPath
- if ctx.InstallInTestcases() {
- var archDir string
- if !ctx.Host() {
- archDir = ctx.DeviceConfig().DeviceArch()
- }
- installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir)
- } else {
- installDir = android.PathForModuleInstall(ctx, "framework")
- }
- ctx.InstallFile(installDir, jarName, outputFile)
- }
+ j.maybeInstall(ctx, jarName, outputFile)
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
@@ -1587,6 +1742,24 @@
})
}
+func (j *Import) maybeInstall(ctx android.ModuleContext, jarName string, outputFile android.Path) {
+ if !Bool(j.properties.Installable) {
+ return
+ }
+
+ var installDir android.InstallPath
+ if ctx.InstallInTestcases() {
+ var archDir string
+ if !ctx.Host() {
+ archDir = ctx.DeviceConfig().DeviceArch()
+ }
+ installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir)
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "framework")
+ }
+ ctx.InstallFile(installDir, jarName, outputFile)
+}
+
func (j *Import) OutputFiles(tag string) (android.Paths, error) {
switch tag {
case "", ".jar":
@@ -1885,9 +2058,7 @@
return module
}
-//
// Defaults
-//
type Defaults struct {
android.ModuleBase
android.DefaultsModuleBase
@@ -1902,29 +2073,29 @@
//
// Example:
//
-// java_defaults {
-// name: "example_defaults",
-// srcs: ["common/**/*.java"],
-// javacflags: ["-Xlint:all"],
-// aaptflags: ["--auto-add-overlay"],
-// }
+// java_defaults {
+// name: "example_defaults",
+// srcs: ["common/**/*.java"],
+// javacflags: ["-Xlint:all"],
+// aaptflags: ["--auto-add-overlay"],
+// }
//
-// java_library {
-// name: "example",
-// defaults: ["example_defaults"],
-// srcs: ["example/**/*.java"],
-// }
+// java_library {
+// name: "example",
+// defaults: ["example_defaults"],
+// srcs: ["example/**/*.java"],
+// }
//
// is functionally identical to:
//
-// java_library {
-// name: "example",
-// srcs: [
-// "common/**/*.java",
-// "example/**/*.java",
-// ],
-// javacflags: ["-Xlint:all"],
-// }
+// java_library {
+// name: "example",
+// srcs: [
+// "common/**/*.java",
+// "example/**/*.java",
+// ],
+// javacflags: ["-Xlint:all"],
+// }
func DefaultsFactory() android.Module {
module := &Defaults{}
@@ -2162,12 +2333,12 @@
var deps bazel.LabelList
if m.properties.Libs != nil {
- deps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Libs))
+ deps.Append(android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(m.properties.Libs))))
}
var staticDeps bazel.LabelList
if m.properties.Static_libs != nil {
- staticDeps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Static_libs))
+ staticDeps.Append(android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(m.properties.Static_libs))))
}
protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition])
@@ -2322,5 +2493,54 @@
props := bazel.BazelTargetModuleProperties{Rule_class: "java_import"}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: android.RemoveOptionalPrebuiltPrefix(i.Name())}, attrs)
+}
+var _ android.MixedBuildBuildable = (*Import)(nil)
+
+func (i *Import) getBazelModuleLabel(ctx android.BaseModuleContext) string {
+ return android.RemoveOptionalPrebuiltPrefixFromBazelLabel(i.GetBazelLabel(ctx, i))
+}
+
+func (i *Import) ProcessBazelQueryResponse(ctx android.ModuleContext) {
+ i.commonBuildActions(ctx)
+
+ bazelCtx := ctx.Config().BazelContext
+ filePaths, err := bazelCtx.GetOutputFiles(i.getBazelModuleLabel(ctx), android.GetConfigKey(ctx))
+ if err != nil {
+ ctx.ModuleErrorf(err.Error())
+ return
+ }
+
+ bazelJars := android.Paths{}
+ for _, bazelOutputFile := range filePaths {
+ bazelJars = append(bazelJars, android.PathForBazelOut(ctx, bazelOutputFile))
+ }
+
+ jarName := android.RemoveOptionalPrebuiltPrefix(i.Name()) + ".jar"
+ outputFile := android.PathForModuleOut(ctx, "bazelCombined", jarName)
+ TransformJarsToJar(ctx, outputFile, "combine prebuilt jars", bazelJars,
+ android.OptionalPath{}, // manifest
+ false, // stripDirEntries
+ []string{}, // filesToStrip
+ []string{}, // dirsToStrip
+ )
+ i.combinedClasspathFile = outputFile
+
+ ctx.SetProvider(JavaInfoProvider, JavaInfo{
+ HeaderJars: android.PathsIfNonNil(i.combinedClasspathFile),
+ ImplementationAndResourcesJars: android.PathsIfNonNil(i.combinedClasspathFile),
+ ImplementationJars: android.PathsIfNonNil(i.combinedClasspathFile),
+ //TODO(b/240308299) include AIDL information from Bazel
+ })
+
+ i.maybeInstall(ctx, jarName, outputFile)
+}
+
+func (i *Import) QueueBazelCall(ctx android.BaseModuleContext) {
+ bazelCtx := ctx.Config().BazelContext
+ bazelCtx.QueueBazelRequest(i.getBazelModuleLabel(ctx), cquery.GetOutputFiles, android.GetConfigKey(ctx))
+}
+
+func (i *Import) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
+ return true
}
diff --git a/java/java_test.go b/java/java_test.go
index 4c93824..9e5cf0c 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -723,9 +723,9 @@
t.Errorf("atestNoOptimize should not optimize APK")
}
- atestDefault := ctx.ModuleForTests("atestDefault", "android_common").MaybeRule("r8")
+ atestDefault := ctx.ModuleForTests("atestDefault", "android_common").MaybeRule("d8")
if atestDefault.Output == nil {
- t.Errorf("atestDefault should optimize APK")
+ t.Errorf("atestDefault should not optimize APK")
}
}
@@ -1498,62 +1498,217 @@
}
func TestDataDeviceBinsBuildsDeviceBinary(t *testing.T) {
- bp := `
+ testCases := []struct {
+ dataDeviceBinType string
+ depCompileMultilib string
+ variants []string
+ expectedError string
+ }{
+ {
+ dataDeviceBinType: "first",
+ depCompileMultilib: "first",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ dataDeviceBinType: "first",
+ depCompileMultilib: "both",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ // this is true because our testing framework is set up with
+ // Targets ~ [<64bit target>, <32bit target>], where 64bit is "first"
+ dataDeviceBinType: "first",
+ depCompileMultilib: "32",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "first",
+ depCompileMultilib: "64",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ dataDeviceBinType: "both",
+ depCompileMultilib: "both",
+ variants: []string{
+ "android_arm_armv7-a-neon",
+ "android_arm64_armv8-a",
+ },
+ },
+ {
+ dataDeviceBinType: "both",
+ depCompileMultilib: "32",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "both",
+ depCompileMultilib: "64",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "both",
+ depCompileMultilib: "first",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "32",
+ depCompileMultilib: "32",
+ variants: []string{"android_arm_armv7-a-neon"},
+ },
+ {
+ dataDeviceBinType: "32",
+ depCompileMultilib: "first",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "32",
+ depCompileMultilib: "both",
+ variants: []string{"android_arm_armv7-a-neon"},
+ },
+ {
+ dataDeviceBinType: "32",
+ depCompileMultilib: "64",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "64",
+ depCompileMultilib: "64",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ dataDeviceBinType: "64",
+ depCompileMultilib: "both",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ dataDeviceBinType: "64",
+ depCompileMultilib: "first",
+ variants: []string{"android_arm64_armv8-a"},
+ },
+ {
+ dataDeviceBinType: "64",
+ depCompileMultilib: "32",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "prefer32",
+ depCompileMultilib: "32",
+ variants: []string{"android_arm_armv7-a-neon"},
+ },
+ {
+ dataDeviceBinType: "prefer32",
+ depCompileMultilib: "both",
+ variants: []string{"android_arm_armv7-a-neon"},
+ },
+ {
+ dataDeviceBinType: "prefer32",
+ depCompileMultilib: "first",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ {
+ dataDeviceBinType: "prefer32",
+ depCompileMultilib: "64",
+ expectedError: `Android.bp:2:3: dependency "bar" of "foo" missing variant`,
+ },
+ }
+
+ bpTemplate := `
java_test_host {
name: "foo",
srcs: ["test.java"],
- data_device_bins: ["bar"],
+ data_device_bins_%s: ["bar"],
}
cc_binary {
name: "bar",
+ compile_multilib: "%s",
}
`
- ctx := android.GroupFixturePreparers(
- PrepareForIntegrationTestWithJava,
- ).RunTestWithBp(t, bp)
+ for _, tc := range testCases {
+ bp := fmt.Sprintf(bpTemplate, tc.dataDeviceBinType, tc.depCompileMultilib)
- buildOS := ctx.Config.BuildOS.String()
- fooVariant := ctx.ModuleForTests("foo", buildOS+"_common")
- barVariant := ctx.ModuleForTests("bar", "android_arm64_armv8-a")
- fooMod := fooVariant.Module().(*TestHost)
+ errorHandler := android.FixtureExpectsNoErrors
+ if tc.expectedError != "" {
+ errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedError)
+ }
- relocated := barVariant.Output("bar")
- expectedInput := "out/soong/.intermediates/bar/android_arm64_armv8-a/unstripped/bar"
- android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
+ testName := fmt.Sprintf(`data_device_bins_%s with compile_multilib:"%s"`, tc.dataDeviceBinType, tc.depCompileMultilib)
+ t.Run(testName, func(t *testing.T) {
+ ctx := android.GroupFixturePreparers(PrepareForIntegrationTestWithJava).
+ ExtendWithErrorHandler(errorHandler).
+ RunTestWithBp(t, bp)
+ if tc.expectedError != "" {
+ return
+ }
- entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, fooMod)[0]
- expectedData := []string{
- "out/soong/.intermediates/bar/android_arm64_armv8-a/bar:bar",
+ buildOS := ctx.Config.BuildOS.String()
+ fooVariant := ctx.ModuleForTests("foo", buildOS+"_common")
+ fooMod := fooVariant.Module().(*TestHost)
+ entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, fooMod)[0]
+
+ expectedAutogenConfig := `<option name="push-file" key="bar" value="/data/local/tests/unrestricted/foo/bar" />`
+ autogen := fooVariant.Rule("autogen")
+ if !strings.Contains(autogen.Args["extraConfigs"], expectedAutogenConfig) {
+ t.Errorf("foo extraConfigs %v does not contain %q", autogen.Args["extraConfigs"], expectedAutogenConfig)
+ }
+
+ expectedData := []string{}
+ for _, variant := range tc.variants {
+ barVariant := ctx.ModuleForTests("bar", variant)
+ relocated := barVariant.Output("bar")
+ expectedInput := fmt.Sprintf("out/soong/.intermediates/bar/%s/unstripped/bar", variant)
+ android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
+
+ expectedData = append(expectedData, fmt.Sprintf("out/soong/.intermediates/bar/%s/bar:bar", variant))
+ }
+
+ actualData := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"]
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", ctx.Config, expectedData, actualData)
+ })
}
- actualData := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"]
- android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", ctx.Config, expectedData, actualData)
}
-func TestDataDeviceBinsAutogenTradefedConfig(t *testing.T) {
+func TestImportMixedBuild(t *testing.T) {
bp := `
- java_test_host {
- name: "foo",
- srcs: ["test.java"],
- data_device_bins: ["bar"],
- }
-
- cc_binary {
- name: "bar",
+ java_import {
+ name: "baz",
+ jars: [
+ "test1.jar",
+ "test2.jar",
+ ],
+ bazel_module: { label: "//foo/bar:baz" },
}
`
ctx := android.GroupFixturePreparers(
- PrepareForIntegrationTestWithJava,
+ prepareForJavaTest,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToOutputFiles: map[string][]string{
+ "//foo/bar:baz": []string{"test1.jar", "test2.jar"},
+ },
+ }
+ }),
).RunTestWithBp(t, bp)
- buildOS := ctx.Config.BuildOS.String()
- fooModule := ctx.ModuleForTests("foo", buildOS+"_common")
- expectedAutogenConfig := `<option name="push-file" key="bar" value="/data/local/tests/unrestricted/foo/bar" />`
+ bazMod := ctx.ModuleForTests("baz", "android_common").Module()
+ producer := bazMod.(android.OutputFileProducer)
+ expectedOutputFiles := []string{".intermediates/baz/android_common/bazelCombined/baz.jar"}
- autogen := fooModule.Rule("autogen")
- if !strings.Contains(autogen.Args["extraConfigs"], expectedAutogenConfig) {
- t.Errorf("foo extraConfigs %v does not contain %q", autogen.Args["extraConfigs"], expectedAutogenConfig)
+ outputFiles, err := producer.OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting java_import outputfiles %s", err)
}
+ actualOutputFiles := android.NormalizePathsForTesting(outputFiles)
+ android.AssertDeepEquals(t, "Output files are produced", expectedOutputFiles, actualOutputFiles)
+
+ javaInfoProvider := ctx.ModuleProvider(bazMod, JavaInfoProvider)
+ javaInfo, ok := javaInfoProvider.(JavaInfo)
+ if !ok {
+ t.Error("could not get JavaInfo from java_import module")
+ }
+ android.AssertDeepEquals(t, "Header JARs are produced", expectedOutputFiles, android.NormalizePathsForTesting(javaInfo.HeaderJars))
+ android.AssertDeepEquals(t, "Implementation/Resources JARs are produced", expectedOutputFiles, android.NormalizePathsForTesting(javaInfo.ImplementationAndResourcesJars))
+ android.AssertDeepEquals(t, "Implementation JARs are produced", expectedOutputFiles, android.NormalizePathsForTesting(javaInfo.ImplementationJars))
}
diff --git a/java/kotlin.go b/java/kotlin.go
index 903c624..9bff5ea 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -119,9 +119,8 @@
"srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(),
"kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(),
"emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(),
- // http://b/69160377 kotlinc only supports -jvm-target 1.6 and 1.8
- "kotlinJvmTarget": "1.8",
- "name": kotlinName,
+ "kotlinJvmTarget": flags.javaVersion.StringForKotlinc(),
+ "name": kotlinName,
},
})
}
diff --git a/java/lint.go b/java/lint.go
index 22c9ec4..6774620 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -17,6 +17,7 @@
import (
"fmt"
"sort"
+ "strconv"
"strings"
"github.com/google/blueprint/proptools"
@@ -60,6 +61,11 @@
// If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
Strict_updatability_linting *bool
+
+ // Treat the code in this module as test code for @VisibleForTesting enforcement.
+ // This will be true by default for test module types, false otherwise.
+ // If soong gets support for testonly, this flag should be replaced with that.
+ Test *bool
}
}
@@ -73,11 +79,10 @@
classpath android.Paths
classes android.Path
extraLintCheckJars android.Paths
- test bool
library bool
- minSdkVersion android.ApiLevel
- targetSdkVersion android.ApiLevel
- compileSdkVersion android.ApiLevel
+ minSdkVersion int
+ targetSdkVersion int
+ compileSdkVersion int
compileSdkKind android.SdkKind
javaLanguageLevel string
kotlinLanguageLevel string
@@ -209,7 +214,7 @@
return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
}
-func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
+func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path) lintPaths {
projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
// Lint looks for a lint.xml file next to the project.xml file, give it one.
configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
@@ -228,7 +233,7 @@
if l.library {
cmd.Flag("--library")
}
- if l.test {
+ if proptools.BoolDefault(l.properties.Lint.Test, false) {
cmd.Flag("--test")
}
if l.manifest != nil {
@@ -240,8 +245,7 @@
// TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
// lint separately.
- srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
- cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
+ cmd.FlagWithInput("--srcs ", srcsList)
cmd.FlagWithInput("--generated_srcs ", srcJarList)
@@ -299,8 +303,8 @@
Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
- Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
- l.minSdkVersion.String(), l.targetSdkVersion.String()).
+ Textf(`echo " <uses-sdk android:minSdkVersion='%d' android:targetSdkVersion='%d'/>" &&`,
+ l.minSdkVersion, l.targetSdkVersion).
Text(`echo "</manifest>"`).
Text(") >").Output(manifestPath)
@@ -325,7 +329,7 @@
return
}
- if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 {
+ if l.minSdkVersion != l.compileSdkVersion {
l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
_, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
if len(filtered) != 0 {
@@ -337,6 +341,14 @@
ctx.PropertyErrorf("lint.disabled_checks",
"Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
}
+
+ // TODO(b/238784089): Remove this workaround when the NewApi issues have been addressed in PermissionController
+ if ctx.ModuleName() == "PermissionController" {
+ l.extraMainlineLintErrors = android.FilterListPred(l.extraMainlineLintErrors, func(s string) bool {
+ return s != "NewApi"
+ })
+ l.properties.Lint.Warning_checks = append(l.properties.Lint.Warning_checks, "NewApi")
+ }
}
extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
@@ -372,7 +384,11 @@
rule.Temporary(manifest)
}
- lintPaths := l.writeLintProjectXML(ctx, rule)
+ srcsList := android.PathForModuleOut(ctx, "lint", "lint-srcs.list")
+ srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
+ rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList)
+
+ lintPaths := l.writeLintProjectXML(ctx, rule, srcsList)
html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
@@ -427,11 +443,12 @@
FlagWithOutput("--html ", html).
FlagWithOutput("--text ", text).
FlagWithOutput("--xml ", xml).
- FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()).
+ FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
FlagWithArg("--java-language-level ", l.javaLanguageLevel).
FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
Flag("--exitcode").
+ Flag("--apply-suggestions"). // applies suggested fixes to files in the sandbox
Flags(l.properties.Lint.Flags).
Implicit(annotationsZipPath).
Implicit(apiVersionsXMLPath)
@@ -457,6 +474,13 @@
// The HTML output contains a date, remove it to make the output deterministic.
rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
+ // The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
+ // export them out of the sandbox.
+ rule.Command().BuiltTool("soong_zip").
+ FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")).
+ FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))).
+ FlagWithInput("-r ", srcsList)
+
rule.Build("lint", "lint")
l.outputs = lintOutputs{
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 1eee354..01e7e6e 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -6,6 +6,7 @@
--disable_check AnimatorKeep
--disable_check AppBundleLocaleChanges
+--disable_check AppCompatCustomView
--disable_check BlockedPrivateApi
--disable_check CustomSplashScreen
--disable_check CustomX509TrustManager
@@ -22,6 +23,7 @@
--disable_check PrivateApi
--disable_check ProtectedPermissions
--disable_check QueryPermissionsNeeded
+--disable_check ReservedSystemPermission
--disable_check ScopedStorage
--disable_check ServiceCast
--disable_check SoonBlockedPrivateApi
@@ -100,6 +102,8 @@
--warning_check CoarseFineLocation
--warning_check IntentFilterExportedReceiver
+--warning_check MissingInflatedId
+--warning_check NotificationPermission
--warning_check QueryAllPackagesPermission
--warning_check RemoteViewLayout
--warning_check SupportAnnotationUsage
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 6257e49..10c9187 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -272,7 +272,9 @@
entries := android.AndroidMkEntriesForTest(t, result.TestContext, platformBootclasspath)
goals := entries[0].GetDistForGoals(platformBootclasspath)
android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0])
- android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[1]))
+ android.AssertStringDoesContain(t, "platform dist goals meta check", goals[1], "$(if $(strip $(ALL_TARGETS.")
+ android.AssertStringDoesContain(t, "platform dist goals meta assign", goals[1], "),,$(eval ALL_TARGETS.")
+ android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[2]))
}
func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) {
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index f442ddf..1c42495 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -26,12 +26,14 @@
func init() {
registerPlatformCompatConfigBuildComponents(android.InitRegistrationContext)
- android.RegisterSdkMemberType(&compatConfigMemberType{
- SdkMemberTypeBase: android.SdkMemberTypeBase{
- PropertyName: "compat_configs",
- SupportsSdk: true,
- },
- })
+ android.RegisterSdkMemberType(CompatConfigSdkMemberType)
+}
+
+var CompatConfigSdkMemberType = &compatConfigMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "compat_configs",
+ SupportsSdk: true,
+ },
}
func registerPlatformCompatConfigBuildComponents(ctx android.RegistrationContext) {
diff --git a/java/robolectric.go b/java/robolectric.go
index f719521..71ffdb1 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -23,6 +23,7 @@
"android/soong/android"
"android/soong/java/config"
"android/soong/tradefed"
+ "github.com/google/blueprint/proptools"
)
func init() {
@@ -344,7 +345,7 @@
&module.testProperties)
module.Module.dexpreopter.isTest = true
- module.Module.linter.test = true
+ module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
module.testProperties.Test_suites = []string{"robolectric-tests"}
diff --git a/java/rro.go b/java/rro.go
index be84aff..c12e748 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -51,6 +51,9 @@
// Name of the signing certificate lineage file.
Lineage *string
+ // For overriding the --rotation-min-sdk-version property of apksig
+ RotationMinSdkVersion *string
+
// optional theme name. If specified, the overlay package will be applied
// only when the ro.boot.vendor.overlay.theme system property is set to the same value.
Theme *string
@@ -142,14 +145,17 @@
r.aapt.buildActions(ctx, r, nil, nil, aaptLinkFlags...)
// Sign the built package
- _, certificates := collectAppDeps(ctx, r, false, false)
+ _, _, certificates := collectAppDeps(ctx, r, false, false)
certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
var lineageFile android.Path
if lineage := String(r.properties.Lineage); lineage != "" {
lineageFile = android.PathForModuleSrc(ctx, lineage)
}
- SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile)
+
+ rotationMinSdkVersion := String(r.properties.RotationMinSdkVersion)
+
+ SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile, rotationMinSdkVersion)
r.certificate = certificates[0]
r.outputFile = signed
@@ -173,6 +179,10 @@
return r.SdkVersion(ctx)
}
+func (r *RuntimeResourceOverlay) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, "")
+}
+
func (r *RuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
return r.SdkVersion(ctx)
}
diff --git a/java/rro_test.go b/java/rro_test.go
index be0d7ba..00ba5ba 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -33,6 +33,7 @@
name: "foo",
certificate: "platform",
lineage: "lineage.bin",
+ rotationMinSdkVersion: "32",
product_specific: true,
static_libs: ["bar"],
resource_libs: ["baz"],
@@ -89,13 +90,14 @@
t.Errorf("Resource lib flag %q missing in aapt2 link flags: %q", resourceLibFlag, aapt2Flags)
}
- // Check cert signing flag.
+ // Check cert signing flags.
signedApk := m.Output("signed/foo.apk")
- lineageFlag := signedApk.Args["flags"]
- expectedLineageFlag := "--lineage lineage.bin"
- if expectedLineageFlag != lineageFlag {
- t.Errorf("Incorrect signing lineage flags, expected: %q, got: %q", expectedLineageFlag, lineageFlag)
+ actualCertSigningFlags := signedApk.Args["flags"]
+ expectedCertSigningFlags := "--lineage lineage.bin --rotation-min-sdk-version 32"
+ if expectedCertSigningFlags != actualCertSigningFlags {
+ t.Errorf("Incorrect cert signing flags, expected: %q, got: %q", expectedCertSigningFlags, actualCertSigningFlags)
}
+
signingFlag := signedApk.Args["certificates"]
expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
if expected != signingFlag {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 8778937..490c031 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -437,7 +437,7 @@
// Determines whether a runtime implementation library is built; defaults to false.
//
// If true then it also prevents the module from being used as a shared module, i.e.
- // it is as is shared_library: false, was set.
+ // it is as if shared_library: false, was set.
Api_only *bool
// local files that are used within user customized droiddoc options.
@@ -2700,7 +2700,10 @@
`"current" is not an allowed value for this attribute`)
return ""
}
- return formattedOptionalAttribute(attrName, value)
+ // "safeValue" is safe because it translates finalized codenames to a string
+ // with their SDK int.
+ safeValue := apiLevel.String()
+ return formattedOptionalAttribute(attrName, &safeValue)
}
// formats an attribute for the xml permissions file if the value is not null
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index fa61ea6..a2cd261 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -24,12 +24,7 @@
func init() {
registerSystemserverClasspathBuildComponents(android.InitRegistrationContext)
- android.RegisterSdkMemberType(&systemServerClasspathFragmentMemberType{
- SdkMemberTypeBase: android.SdkMemberTypeBase{
- PropertyName: "systemserverclasspath_fragments",
- SupportsSdk: true,
- },
- })
+ android.RegisterSdkMemberType(SystemServerClasspathFragmentSdkMemberType)
}
func registerSystemserverClasspathBuildComponents(ctx android.RegistrationContext) {
@@ -38,6 +33,17 @@
ctx.RegisterModuleType("prebuilt_systemserverclasspath_fragment", prebuiltSystemServerClasspathModuleFactory)
}
+var SystemServerClasspathFragmentSdkMemberType = &systemServerClasspathFragmentMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "systemserverclasspath_fragments",
+ SupportsSdk: true,
+
+ // Support for adding systemserverclasspath_fragments to the sdk snapshot was only added in
+ // Tiramisu.
+ SupportedBuildReleaseSpecification: "Tiramisu+",
+ },
+}
+
type platformSystemServerClasspathModule struct {
android.ModuleBase
diff --git a/java/testing.go b/java/testing.go
index 4000334..511cc5d 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -54,6 +54,8 @@
"build/soong/java/lint_defaults.txt": nil,
// Needed for apps that do not provide their own.
"build/make/target/product/security": nil,
+ // Required to generate Java used-by API coverage
+ "build/soong/scripts/gen_java_usedby_apex.sh": nil,
}.AddToFixture(),
)
diff --git a/licenses/Android.bp b/licenses/Android.bp
index 8db001f..133f7f7 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -32,6 +32,15 @@
}
license_kind {
+ name: "BSD-Like-Binary-Only",
+ conditions: [
+ "notice",
+ "by_exception_only",
+ "proprietary",
+ ],
+}
+
+license_kind {
name: "SPDX-license-identifier-0BSD",
conditions: ["unencumbered"],
url: "https://spdx.org/licenses/0BSD",
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 003b275..412a23b 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -22,6 +22,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/bazel"
"android/soong/cc"
"android/soong/etc"
)
@@ -36,7 +37,7 @@
}
func registerLinkerConfigBuildComponent(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("linker_config", linkerConfigFactory)
+ ctx.RegisterModuleType("linker_config", LinkerConfigFactory)
}
type linkerConfigProperties struct {
@@ -52,6 +53,7 @@
type linkerConfig struct {
android.ModuleBase
+ android.BazelModuleBase
properties linkerConfigProperties
outputFilePath android.OutputPath
@@ -100,6 +102,28 @@
ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
}
+type linkerConfigAttributes struct {
+ Src bazel.LabelAttribute
+}
+
+func (l *linkerConfig) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ if l.properties.Src == nil {
+ ctx.PropertyErrorf("src", "empty src is not supported")
+ return
+ }
+ src := android.BazelLabelForModuleSrcSingle(ctx, *l.properties.Src)
+ targetModuleProperties := bazel.BazelTargetModuleProperties{
+ Rule_class: "linker_config",
+ Bzl_load_location: "//build/bazel/rules:linker_config.bzl",
+ }
+ ctx.CreateBazelTargetModule(
+ targetModuleProperties,
+ android.CommonAttributes{Name: l.Name()},
+ &linkerConfigAttributes{
+ Src: bazel.LabelAttribute{Value: &src},
+ })
+}
+
func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder,
input android.Path, otherModules []android.Module, output android.OutputPath) {
@@ -141,10 +165,11 @@
// linker_config generates protobuf file from json file. This protobuf file will be used from
// linkerconfig while generating ld.config.txt. Format of this file can be found from
// https://android.googlesource.com/platform/system/linkerconfig/+/master/README.md
-func linkerConfigFactory() android.Module {
+func LinkerConfigFactory() android.Module {
m := &linkerConfig{}
m.AddProperties(&m.properties)
android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibFirst)
+ android.InitBazelModule(m)
return m
}
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index e59146b..2707f0c 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -830,21 +830,13 @@
pathPattern = append(pathPattern, chunk)
}
}
- if pathPattern[0] == "" && len(ctx.includeTops) > 0 {
- // If pattern starts from the top. restrict it to the directories where
- // we know inherit-product uses dynamically calculated path.
- for _, p := range ctx.includeTops {
- pathPattern[0] = p
- matchingPaths = append(matchingPaths, ctx.findMatchingPaths(pathPattern)...)
- }
- } else {
- matchingPaths = ctx.findMatchingPaths(pathPattern)
+ if len(pathPattern) == 1 {
+ pathPattern = append(pathPattern, "")
}
+ matchingPaths = ctx.findMatchingPaths(pathPattern)
needsWarning = pathPattern[0] == "" && len(ctx.includeTops) == 0
} else if len(ctx.includeTops) > 0 {
- for _, p := range ctx.includeTops {
- matchingPaths = append(matchingPaths, ctx.findMatchingPaths([]string{p, ""})...)
- }
+ matchingPaths = append(matchingPaths, ctx.findMatchingPaths([]string{"", ""})...)
} else {
return []starlarkNode{ctx.newBadNode(v, "inherit-product/include argument is too complex")}
}
@@ -872,17 +864,31 @@
}
// Create regular expression from the pattern
- s_regexp := "^" + regexp.QuoteMeta(pattern[0])
+ regexString := "^" + regexp.QuoteMeta(pattern[0])
for _, s := range pattern[1:] {
- s_regexp += ".*" + regexp.QuoteMeta(s)
+ regexString += ".*" + regexp.QuoteMeta(s)
}
- s_regexp += "$"
- rex := regexp.MustCompile(s_regexp)
+ regexString += "$"
+ rex := regexp.MustCompile(regexString)
+
+ includeTopRegexString := ""
+ if len(ctx.includeTops) > 0 {
+ for i, top := range ctx.includeTops {
+ if i > 0 {
+ includeTopRegexString += "|"
+ }
+ includeTopRegexString += "^" + regexp.QuoteMeta(top)
+ }
+ } else {
+ includeTopRegexString = ".*"
+ }
+
+ includeTopRegex := regexp.MustCompile(includeTopRegexString)
// Now match
var res []string
for _, p := range files {
- if rex.MatchString(p) {
+ if rex.MatchString(p) && includeTopRegex.MatchString(p) {
res = append(res, p)
}
}
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index a09764c..31555d3 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -1157,6 +1157,8 @@
#RBC# include_top vendor/foo1
$(call inherit-product,$(MY_OTHER_PATH))
#RBC# include_top vendor/foo1
+$(call inherit-product,vendor/$(MY_OTHER_PATH))
+#RBC# include_top vendor/foo1
$(foreach f,$(MY_MAKEFILES), \
$(call inherit-product,$(f)))
`,
@@ -1180,6 +1182,13 @@
if not _varmod_init:
rblf.mkerror("product.mk", "Cannot find %s" % (g.get("MY_OTHER_PATH", "")))
rblf.inherit(handle, _varmod, _varmod_init)
+ _entry = {
+ "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
+ }.get("vendor/%s" % g.get("MY_OTHER_PATH", ""))
+ (_varmod, _varmod_init) = _entry if _entry else (None, None)
+ if not _varmod_init:
+ rblf.mkerror("product.mk", "Cannot find %s" % ("vendor/%s" % g.get("MY_OTHER_PATH", "")))
+ rblf.inherit(handle, _varmod, _varmod_init)
for f in rblf.words(g.get("MY_MAKEFILES", "")):
_entry = {
"vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
diff --git a/multitree/Android.bp b/multitree/Android.bp
index 9b16d20..78c4962 100644
--- a/multitree/Android.bp
+++ b/multitree/Android.bp
@@ -10,6 +10,7 @@
"soong-android",
],
srcs: [
+ "api_imports.go",
"api_surface.go",
"export.go",
"metadata.go",
diff --git a/multitree/api_imports.go b/multitree/api_imports.go
new file mode 100644
index 0000000..2c4cf80
--- /dev/null
+++ b/multitree/api_imports.go
@@ -0,0 +1,88 @@
+// 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 multitree
+
+import (
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+var (
+ apiImportNameSuffix = ".apiimport"
+)
+
+func init() {
+ RegisterApiImportsModule(android.InitRegistrationContext)
+}
+
+func RegisterApiImportsModule(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("api_imports", apiImportsFactory)
+}
+
+type ApiImports struct {
+ android.ModuleBase
+ properties apiImportsProperties
+}
+
+type apiImportsProperties struct {
+ Shared_libs []string // List of C shared libraries from API surfaces
+ Header_libs []string // List of C header libraries from API surfaces
+}
+
+// 'api_imports' is a module which describes modules available from API surfaces.
+// This module is required to get the list of all imported API modules, because
+// it is discouraged to loop and fetch all modules from its type information. The
+// only module with name 'api_imports' will be used from the build.
+func apiImportsFactory() android.Module {
+ module := &ApiImports{}
+ module.AddProperties(&module.properties)
+ android.InitAndroidModule(module)
+ return module
+}
+
+func (imports *ApiImports) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // ApiImport module does not generate any build actions
+}
+
+type ApiImportInfo struct {
+ SharedLibs, HeaderLibs map[string]string
+}
+
+var ApiImportsProvider = blueprint.NewMutatorProvider(ApiImportInfo{}, "deps")
+
+// Store module lists into ApiImportInfo and share it over mutator provider.
+func (imports *ApiImports) DepsMutator(ctx android.BottomUpMutatorContext) {
+ generateNameMapWithSuffix := func(names []string) map[string]string {
+ moduleNameMap := make(map[string]string)
+ for _, name := range names {
+ moduleNameMap[name] = name + apiImportNameSuffix
+ }
+
+ return moduleNameMap
+ }
+
+ sharedLibs := generateNameMapWithSuffix(imports.properties.Shared_libs)
+ headerLibs := generateNameMapWithSuffix(imports.properties.Header_libs)
+
+ ctx.SetProvider(ApiImportsProvider, ApiImportInfo{
+ SharedLibs: sharedLibs,
+ HeaderLibs: headerLibs,
+ })
+}
+
+func GetApiImportSuffix() string {
+ return apiImportNameSuffix
+}
diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go
index d1cbd8f..fbb6212 100644
--- a/provenance/provenance_singleton.go
+++ b/provenance/provenance_singleton.go
@@ -35,10 +35,10 @@
mergeProvenanceMetaData = pctx.AndroidStaticRule("mergeProvenanceMetaData",
blueprint.RuleParams{
- Command: `rm -rf $out $out.temp && ` +
+ Command: `rm -rf $out && ` +
`echo "# proto-file: build/soong/provenance/proto/provenance_metadata.proto" > $out && ` +
`echo "# proto-message: ProvenanceMetaDataList" >> $out && ` +
- `touch $out.temp && cat $out.temp $in | grep -v "^#.*" >> $out && rm -rf $out.temp`,
+ `for file in $in; do echo '' >> $out; echo 'metadata {' | cat - $$file | grep -Ev "^#.*|^$$" >> $out; echo '}' >> $out; done`,
})
)
diff --git a/python/binary.go b/python/binary.go
index 99c6259..af29bb6 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -38,6 +38,7 @@
Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Python_version *string
+ Imports bazel.StringListAttribute
}
func pythonBinaryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
@@ -75,6 +76,7 @@
Srcs: baseAttrs.Srcs,
Deps: baseAttrs.Deps,
Python_version: python_version,
+ Imports: baseAttrs.Imports,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/python/library.go b/python/library.go
index 3a27591..df92df4 100644
--- a/python/library.go
+++ b/python/library.go
@@ -17,9 +17,6 @@
// This file contains the module types for building Python library.
import (
- "path/filepath"
- "strings"
-
"android/soong/android"
"android/soong/bazel"
@@ -50,6 +47,10 @@
Srcs_version *string
}
+type bazelPythonProtoLibraryAttributes struct {
+ Deps bazel.LabelListAttribute
+}
+
func pythonLibBp2Build(ctx android.TopDownMutatorContext, m *Module) {
// 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
@@ -68,39 +69,13 @@
// do nothing, since python_version defaults to PY2ANDPY3
}
- // Bazel normally requires `import path.from.top.of.tree` statements in
- // python code, but with soong you can directly import modules from libraries.
- // Add "imports" attributes to the bazel library so it matches soong's behavior.
- imports := "."
- if m.properties.Pkg_path != nil {
- // TODO(b/215119317) This is a hack to handle the fact that we don't convert
- // pkg_path properly right now. If the folder structure that contains this
- // Android.bp file matches pkg_path, we can set imports to an appropriate
- // number of ../..s to emulate moving the files under a pkg_path folder.
- pkg_path := filepath.Clean(*m.properties.Pkg_path)
- if strings.HasPrefix(pkg_path, "/") {
- ctx.ModuleErrorf("pkg_path cannot start with a /: %s", pkg_path)
- return
- }
-
- if !strings.HasSuffix(ctx.ModuleDir(), "/"+pkg_path) && ctx.ModuleDir() != pkg_path {
- ctx.ModuleErrorf("Currently, bp2build only supports pkg_paths that are the same as the folders the Android.bp file is in. pkg_path: %s, module directory: %s", pkg_path, ctx.ModuleDir())
- return
- }
- numFolders := strings.Count(pkg_path, "/") + 1
- dots := make([]string, numFolders)
- for i := 0; i < numFolders; i++ {
- dots[i] = ".."
- }
- imports = strings.Join(dots, "/")
- }
-
baseAttrs := m.makeArchVariantBaseAttributes(ctx)
+
attrs := &bazelPythonLibraryAttributes{
Srcs: baseAttrs.Srcs,
Deps: baseAttrs.Deps,
Srcs_version: python_version,
- Imports: bazel.MakeStringListAttribute([]string{imports}),
+ Imports: baseAttrs.Imports,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/python/python.go b/python/python.go
index b100cc3..eb0d3ca 100644
--- a/python/python.go
+++ b/python/python.go
@@ -131,7 +131,8 @@
Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
// Combines Data and Java_data (invariant)
- Data bazel.LabelListAttribute
+ Data bazel.LabelListAttribute
+ Imports bazel.StringListAttribute
}
// Used to store files of current module after expanding dependencies
@@ -207,6 +208,56 @@
}
}
}
+
+ partitionedSrcs := bazel.PartitionLabelListAttribute(ctx, &attrs.Srcs, bazel.LabelPartitions{
+ "proto": android.ProtoSrcLabelPartition,
+ "py": bazel.LabelPartition{Keep_remainder: true},
+ })
+ attrs.Srcs = partitionedSrcs["py"]
+
+ if !partitionedSrcs["proto"].IsEmpty() {
+ protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"])
+ protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
+
+ pyProtoLibraryName := m.Name() + "_py_proto"
+ ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
+ Rule_class: "py_proto_library",
+ Bzl_load_location: "//build/bazel/rules/python:py_proto.bzl",
+ }, android.CommonAttributes{
+ Name: pyProtoLibraryName,
+ }, &bazelPythonProtoLibraryAttributes{
+ Deps: bazel.MakeSingleLabelListAttribute(protoLabel),
+ })
+
+ attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
+ }
+
+ // Bazel normally requires `import path.from.top.of.tree` statements in
+ // python code, but with soong you can directly import modules from libraries.
+ // Add "imports" attributes to the bazel library so it matches soong's behavior.
+ imports := "."
+ if m.properties.Pkg_path != nil {
+ // TODO(b/215119317) This is a hack to handle the fact that we don't convert
+ // pkg_path properly right now. If the folder structure that contains this
+ // Android.bp file matches pkg_path, we can set imports to an appropriate
+ // number of ../..s to emulate moving the files under a pkg_path folder.
+ pkg_path := filepath.Clean(*m.properties.Pkg_path)
+ if strings.HasPrefix(pkg_path, "/") {
+ ctx.ModuleErrorf("pkg_path cannot start with a /: %s", pkg_path)
+ }
+
+ if !strings.HasSuffix(ctx.ModuleDir(), "/"+pkg_path) && ctx.ModuleDir() != pkg_path {
+ ctx.ModuleErrorf("Currently, bp2build only supports pkg_paths that are the same as the folders the Android.bp file is in. pkg_path: %s, module directory: %s", pkg_path, ctx.ModuleDir())
+ }
+ numFolders := strings.Count(pkg_path, "/") + 1
+ dots := make([]string, numFolders)
+ for i := 0; i < numFolders; i++ {
+ dots[i] = ".."
+ }
+ imports = strings.Join(dots, "/")
+ }
+ attrs.Imports = bazel.MakeStringListAttribute([]string{imports})
+
return attrs
}
@@ -631,7 +682,8 @@
// in order to keep stable order of soong_zip params, we sort the keys here.
roots := android.SortedStringKeys(relativeRootMap)
- parArgs := []string{}
+ // Use -symlinks=false so that the symlinks in the bazel output directory are followed
+ parArgs := []string{"-symlinks=false"}
if pkgPath != "" {
// use package path as path prefix
parArgs = append(parArgs, `-P `+pkgPath)
diff --git a/rust/OWNERS b/rust/OWNERS
index ddaebc5..b595511 100644
--- a/rust/OWNERS
+++ b/rust/OWNERS
@@ -1,5 +1,2 @@
# Additional owner/reviewers for rust rules, including parent directory owners.
per-file * = chiw@google.com, chriswailes@google.com, ivanlozano@google.com, jeffv@google.com, mmaurer@google.com, srhines@google.com
-
-# Limited owners/reviewers of the allowed list.
-per-file allowed_list.go = chiw@google.com, chriswailes@google.com, ivanlozano@google.com, jeffv@google.com, mmaurer@google.com, srhines@google.com
diff --git a/rust/bindgen.go b/rust/bindgen.go
index b4626a0..0199d3a 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -41,10 +41,25 @@
//TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen.
_ = pctx.HostBinToolVariable("bindgenCmd", "bindgen")
+ _ = pctx.VariableFunc("bindgenHostPrebuiltTag", func(ctx android.PackageVarContext) string {
+ if ctx.Config().UseHostMusl() {
+ // This is a hack to use the glibc bindgen binary until we have a musl version checked in.
+ return "linux-x86"
+ } else {
+ return "${config.HostPrebuiltTag}"
+ }
+ })
+ _ = pctx.VariableFunc("bindgenClangLibdir", func(ctx android.PackageVarContext) string {
+ if ctx.Config().UseHostMusl() {
+ return "musl/lib64/"
+ } else {
+ return "lib64/"
+ }
+ })
_ = pctx.SourcePathVariable("bindgenClang",
- "${cc_config.ClangBase}/${config.HostPrebuiltTag}/${bindgenClangVersion}/bin/clang")
+ "${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/bin/clang")
_ = pctx.SourcePathVariable("bindgenLibClang",
- "${cc_config.ClangBase}/${config.HostPrebuiltTag}/${bindgenClangVersion}/lib64/")
+ "${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/${bindgenClangLibdir}")
//TODO(ivanlozano) Switch this to RuleBuilder
bindgen = pctx.AndroidStaticRule("bindgen",
@@ -224,6 +239,11 @@
cflags = append(cflags, "-x c")
}
+ // LLVM_NEXT may contain flags that bindgen doesn't recognise. Turn off unknown flags warning.
+ if ctx.Config().IsEnvTrue("LLVM_NEXT") {
+ cflags = append(cflags, "-Wno-unknown-warning-option")
+ }
+
outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs")
var cmd, cmdDesc string
@@ -279,7 +299,15 @@
ClangProperties: cc.RustBindgenClangProperties{},
}
- module := NewSourceProviderModule(hod, bindgen, false)
+ module := NewSourceProviderModule(hod, bindgen, false, true)
+
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ type stub_props struct {
+ Visibility []string
+ }
+ props := &stub_props{[]string{":__subpackages__"}}
+ ctx.PrependProperties(props)
+ })
return module, bindgen
}
diff --git a/rust/compiler.go b/rust/compiler.go
index bcd58c8..bf6a488 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -371,8 +371,9 @@
if !Bool(compiler.Properties.No_stdlibs) {
for _, stdlib := range config.Stdlibs {
- // If we're building for the build host, use the prebuilt stdlibs
- if ctx.Target().Os == android.Linux || ctx.Target().Os == android.Darwin {
+ // If we're building for the build host, use the prebuilt stdlibs, unless the host
+ // is linux_bionic which doesn't have prebuilts.
+ if ctx.Host() && !ctx.Target().HostCross && ctx.Target().Os != android.LinuxBionic {
stdlib = "prebuilt_" + stdlib
}
deps.Stdlibs = append(deps.Stdlibs, stdlib)
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index 7757c79..be73d69 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -11,11 +11,11 @@
],
srcs: [
"arm_device.go",
+ "arm_linux_host.go",
"arm64_device.go",
"global.go",
"lints.go",
"toolchain.go",
- "allowed_list.go",
"darwin_host.go",
"x86_linux_bionic_host.go",
"x86_linux_host.go",
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
deleted file mode 100644
index 7468579..0000000
--- a/rust/config/allowed_list.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package config
-
-var (
- // When adding a new path below, add a rustfmt.toml file at the root of
- // the repository and enable the rustfmt repo hook. See aosp/1458238
- // for an example.
- // TODO(b/160223496): enable rustfmt globally.
- RustAllowedPaths = []string{
- "device/google/cuttlefish",
- "external/adhd",
- "external/boringssl",
- "external/crosvm",
- "external/libchromeos-rs",
- "external/minijail",
- "external/open-dice",
- "external/rust",
- "external/selinux/libselinux",
- "external/uwb",
- "external/vm_tools/p9",
- "frameworks/native/libs/binder/rust",
- "frameworks/proto_logging/stats",
- "hardware/interfaces/security",
- "hardware/interfaces/uwb",
- "packages/modules/Bluetooth",
- "packages/modules/DnsResolver",
- "packages/modules/Uwb",
- "packages/modules/Virtualization",
- "platform_testing/tests/codecoverage/native/rust",
- "prebuilts/rust",
- "system/core/debuggerd/rust",
- "system/core/libstats/pull_rust",
- "system/core/trusty/libtrusty-rs",
- "system/extras/profcollectd",
- "system/extras/simpleperf",
- "system/hardware/interfaces/keystore2",
- "system/librustutils",
- "system/logging/liblog",
- "system/logging/rust",
- "system/nfc",
- "system/security",
- "system/tools/aidl",
- "tools/security/fuzzing/example_rust_fuzzer",
- "tools/security/fuzzing/orphans",
- "tools/security/remote_provisioning/cert_validator",
- "tools/vendor",
- "vendor/",
- }
-
- DownstreamRustAllowedPaths = []string{
- // Add downstream allowed Rust paths here.
- }
-
- RustModuleTypes = []string{
- // Don't add rust_bindgen or rust_protobuf as these are code generation modules
- // and can be expected to be in paths without Rust code.
- "rust_benchmark",
- "rust_benchmark_host",
- "rust_binary",
- "rust_binary_host",
- "rust_library",
- "rust_library_dylib",
- "rust_library_rlib",
- "rust_ffi",
- "rust_ffi_shared",
- "rust_ffi_static",
- "rust_fuzz",
- "rust_library_host",
- "rust_library_host_dylib",
- "rust_library_host_rlib",
- "rust_ffi_host",
- "rust_ffi_host_shared",
- "rust_ffi_host_static",
- "rust_proc_macro",
- "rust_test",
- "rust_test_host",
- }
-)
diff --git a/rust/config/arm_linux_host.go b/rust/config/arm_linux_host.go
new file mode 100644
index 0000000..22bdaee
--- /dev/null
+++ b/rust/config/arm_linux_host.go
@@ -0,0 +1,147 @@
+// 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 config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ linuxArmRustflags = []string{}
+ linuxArmLinkflags = []string{}
+ linuxArm64Rustflags = []string{}
+ linuxArm64Linkflags = []string{}
+)
+
+func init() {
+ registerToolchainFactory(android.LinuxMusl, android.Arm64, linuxMuslArm64ToolchainFactory)
+ registerToolchainFactory(android.LinuxMusl, android.Arm, linuxMuslArmToolchainFactory)
+
+ pctx.StaticVariable("LinuxToolchainArmRustFlags", strings.Join(linuxArmRustflags, " "))
+ pctx.StaticVariable("LinuxToolchainArmLinkFlags", strings.Join(linuxArmLinkflags, " "))
+ pctx.StaticVariable("LinuxToolchainArm64RustFlags", strings.Join(linuxArm64Rustflags, " "))
+ pctx.StaticVariable("LinuxToolchainArm64LinkFlags", strings.Join(linuxArm64Linkflags, " "))
+}
+
+// Base 64-bit linux rust toolchain
+type toolchainLinuxArm64 struct {
+ toolchain64Bit
+}
+
+func (toolchainLinuxArm64) Supported() bool {
+ return true
+}
+
+func (toolchainLinuxArm64) Bionic() bool {
+ return false
+}
+
+func (t *toolchainLinuxArm64) Name() string {
+ return "arm64"
+}
+
+func (t *toolchainLinuxArm64) ToolchainLinkFlags() string {
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${cc_config.LinuxLldflags} ${cc_config.LinuxArm64Lldflags} " +
+ "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainArm64LinkFlags}"
+}
+
+func (t *toolchainLinuxArm64) ToolchainRustFlags() string {
+ return "${config.LinuxToolchainRustFlags} ${config.LinuxToolchainArm64RustFlags}"
+}
+
+// Specialization of the 64-bit linux rust toolchain for musl. Adds the musl rust triple and
+// linker flags to avoid using the host sysroot.
+type toolchainLinuxMuslArm64 struct {
+ toolchainLinuxArm64
+}
+
+func (t *toolchainLinuxMuslArm64) RustTriple() string {
+ return "aarch64-unknown-linux-musl"
+}
+
+func (t *toolchainLinuxMuslArm64) ToolchainLinkFlags() string {
+ return t.toolchainLinuxArm64.ToolchainLinkFlags() + " " + "${config.LinuxMuslToolchainLinkFlags}"
+}
+
+func (t *toolchainLinuxMuslArm64) ToolchainRustFlags() string {
+ return t.toolchainLinuxArm64.ToolchainRustFlags() + " " + "${config.LinuxMuslToolchainRustFlags}"
+}
+
+func linuxMuslArm64ToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxMuslArm64Singleton
+}
+
+// Base 32-bit linux rust toolchain
+type toolchainLinuxArm struct {
+ toolchain32Bit
+}
+
+func (toolchainLinuxArm) Supported() bool {
+ return true
+}
+
+func (toolchainLinuxArm) Bionic() bool {
+ return false
+}
+
+func (t *toolchainLinuxArm) Name() string {
+ return "arm"
+}
+
+func (toolchainLinuxArm) LibclangRuntimeLibraryArch() string {
+ return "arm"
+}
+
+func (toolchainLinuxArm64) LibclangRuntimeLibraryArch() string {
+ return "arm64"
+}
+
+func (t *toolchainLinuxArm) ToolchainLinkFlags() string {
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${cc_config.LinuxLldflags} ${cc_config.LinuxArmLldflags} " +
+ "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainArmLinkFlags}"
+}
+
+func (t *toolchainLinuxArm) ToolchainRustFlags() string {
+ return "${config.LinuxToolchainRustFlags} ${config.LinuxToolchainArmRustFlags}"
+}
+
+// Specialization of the 32-bit linux rust toolchain for musl. Adds the musl rust triple and
+// linker flags to avoid using the host sysroot.
+type toolchainLinuxMuslArm struct {
+ toolchainLinuxArm
+}
+
+func (t *toolchainLinuxMuslArm) RustTriple() string {
+ return "arm-unknown-linux-musleabihf"
+}
+
+func (t *toolchainLinuxMuslArm) ToolchainLinkFlags() string {
+ return t.toolchainLinuxArm.ToolchainLinkFlags() + " " + "${config.LinuxMuslToolchainLinkFlags}"
+}
+
+func (t *toolchainLinuxMuslArm) ToolchainRustFlags() string {
+ return t.toolchainLinuxArm.ToolchainRustFlags() + " " + "${config.LinuxMuslToolchainRustFlags}"
+}
+
+func linuxMuslArmToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxMuslArmSingleton
+}
+
+var toolchainLinuxMuslArm64Singleton Toolchain = &toolchainLinuxMuslArm64{}
+var toolchainLinuxMuslArmSingleton Toolchain = &toolchainLinuxMuslArm{}
diff --git a/rust/config/global.go b/rust/config/global.go
index d11665c..9acbfb3 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.60.0"
+ RustDefaultVersion = "1.62.0.p1"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2021"
Stdlibs = []string{
@@ -78,7 +78,13 @@
func init() {
pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase)
- pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
+ pctx.VariableConfigMethod("HostPrebuiltTag", func(config android.Config) string {
+ if config.UseHostMusl() {
+ return "linux-musl-x86"
+ } else {
+ return config.PrebuiltOS()
+ }
+ })
pctx.VariableFunc("RustBase", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
diff --git a/rust/coverage.go b/rust/coverage.go
index 651ce6e..5ea481f 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -56,7 +56,7 @@
flags.Coverage = true
coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
flags.RustFlags = append(flags.RustFlags,
- "-Z instrument-coverage", "-g")
+ "-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())
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index f3cd375..0f599d7 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -56,7 +56,7 @@
fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
- rustcCoverageFlags := []string{"-Z instrument-coverage", " -g "}
+ rustcCoverageFlags := []string{"-C instrument-coverage", " -g "}
for _, flag := range rustcCoverageFlags {
missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 55921ba..586095c 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -153,7 +153,7 @@
sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, cc.UnstrippedOutputFile, cc.IsValidSharedDependency)
// Package shared libraries
- files = append(files, cc.GetSharedLibsToZip(sharedLibraries, rustModule, &s.FuzzPackager, archString, &sharedLibraryInstalled)...)
+ files = append(files, cc.GetSharedLibsToZip(sharedLibraries, rustModule, &s.FuzzPackager, archString, "lib", &sharedLibraryInstalled)...)
archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
if !ok {
diff --git a/rust/protobuf.go b/rust/protobuf.go
index 9fe27c4c..88e80fe 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -238,7 +238,7 @@
Properties: ProtobufProperties{},
}
- module := NewSourceProviderModule(hod, protobuf, false)
+ module := NewSourceProviderModule(hod, protobuf, false, false)
return module, protobuf
}
diff --git a/rust/rust.go b/rust/rust.go
index 48419eb..1517e62 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -33,13 +33,6 @@
var pctx = android.NewPackageContext("android/soong/rust")
func init() {
- // Only allow rust modules to be defined for certain projects
-
- android.AddNeverAllowRules(
- android.NeverAllow().
- NotIn(append(config.RustAllowedPaths, config.DownstreamRustAllowedPaths...)...).
- ModuleType(config.RustModuleTypes...))
-
android.RegisterModuleType("rust_defaults", defaultsFactory)
android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
@@ -695,6 +688,19 @@
panic(fmt.Errorf("CoverageFiles called on non-library module: %q", mod.BaseModuleName()))
}
+// Rust does not produce gcno files, and therefore does not produce a coverage archive.
+func (mod *Module) CoverageOutputFile() android.OptionalPath {
+ return android.OptionalPath{}
+}
+
+func (mod *Module) IsNdk(config android.Config) bool {
+ return false
+}
+
+func (mod *Module) IsStubs() bool {
+ return false
+}
+
func (mod *Module) installable(apexInfo android.ApexInfo) bool {
if !proptools.BoolDefault(mod.Installable(), mod.EverInstallable()) {
return false
@@ -1367,6 +1373,11 @@
var commonDepVariations []blueprint.Variation
var snapshotInfo *cc.SnapshotInfo
+ apiImportInfo := cc.GetApiImports(mod, actx)
+ for idx, lib := range deps.SharedLibs {
+ deps.SharedLibs[idx] = cc.GetReplaceModuleName(lib, apiImportInfo.SharedLibs)
+ }
+
if ctx.Os() == android.Android {
deps.SharedLibs, _ = cc.RewriteLibs(mod, &snapshotInfo, actx, ctx.Config(), deps.SharedLibs)
}
@@ -1387,7 +1398,7 @@
rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: rlibVariation})
for _, lib := range deps.Rlibs {
depTag := rlibDepTag
- lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
+ lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
actx.AddVariationDependencies(rlibDepVariations, depTag, lib)
}
@@ -1425,7 +1436,7 @@
if mod.compiler.stdLinkage(ctx) == RlibLinkage {
for _, lib := range deps.Stdlibs {
depTag := rlibDepTag
- lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
+ lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...),
depTag, lib)
@@ -1449,7 +1460,7 @@
for _, lib := range deps.WholeStaticLibs {
depTag := cc.StaticDepTag(true)
- lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs)
+ lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs)
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
@@ -1458,7 +1469,7 @@
for _, lib := range deps.StaticLibs {
depTag := cc.StaticDepTag(false)
- lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs)
+ lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs)
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
@@ -1470,11 +1481,11 @@
crtVariations := cc.GetCrtVariations(ctx, mod)
for _, crt := range deps.CrtBegin {
actx.AddVariationDependencies(crtVariations, cc.CrtBeginDepTag,
- cc.RewriteSnapshotLib(crt, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects))
+ cc.GetReplaceModuleName(crt, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects))
}
for _, crt := range deps.CrtEnd {
actx.AddVariationDependencies(crtVariations, cc.CrtEndDepTag,
- cc.RewriteSnapshotLib(crt, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects))
+ cc.GetReplaceModuleName(crt, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects))
}
if mod.sourceProvider != nil {
@@ -1497,7 +1508,7 @@
// addRlibDependency will add an rlib dependency, rewriting to the snapshot library if available.
func addRlibDependency(actx android.BottomUpMutatorContext, lib string, mod *Module, snapshotInfo *cc.SnapshotInfo, variations []blueprint.Variation) {
- lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
+ lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
actx.AddVariationDependencies(variations, rlibDepTag, lib)
}
diff --git a/rust/sanitize.go b/rust/sanitize.go
index aadc00f..a3c5cb5 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -49,8 +49,7 @@
Memtag_heap *bool `android:"arch_variant"`
}
}
- SanitizerEnabled bool `blueprint:"mutated"`
- SanitizeDepTypes []cc.SanitizerType `blueprint:"mutated"`
+ SanitizerEnabled bool `blueprint:"mutated"`
// Used when we need to place libraries in their own directory, such as ASAN.
InSanitizerDir bool `blueprint:"mutated"`
@@ -175,7 +174,7 @@
}
// Enable Memtag for all components in the include paths (for Aarch64 only)
- if ctx.Arch().ArchType == android.Arm64 {
+ if ctx.Arch().ArchType == android.Arm64 && ctx.Os().Bionic() {
if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
if s.Memtag_heap == nil {
s.Memtag_heap = proptools.BoolPtr(true)
@@ -201,7 +200,7 @@
}
// HWASan requires AArch64 hardware feature (top-byte-ignore).
- if ctx.Arch().ArchType != android.Arm64 {
+ if ctx.Arch().ArchType != android.Arm64 || !ctx.Os().Bionic() {
s.Hwaddress = nil
}
@@ -216,7 +215,7 @@
}
// Memtag_heap is only implemented on AArch64.
- if ctx.Arch().ArchType != android.Arm64 {
+ if ctx.Arch().ArchType != android.Arm64 || !ctx.Os().Bionic() {
s.Memtag_heap = nil
}
@@ -235,7 +234,7 @@
}
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
- if ctx.Arch().ArchType == android.Arm64 {
+ if ctx.Arch().ArchType == android.Arm64 && ctx.Os().Bionic() {
flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
} else {
flags.RustFlags = append(flags.RustFlags, asanFlags...)
@@ -283,13 +282,13 @@
var deps []string
if mod.IsSanitizerEnabled(cc.Asan) ||
- (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType != android.Arm64) {
+ (mod.IsSanitizerEnabled(cc.Fuzzer) && (mctx.Arch().ArchType != android.Arm64 || !mctx.Os().Bionic())) {
variations = append(variations,
blueprint.Variation{Mutator: "link", Variation: "shared"})
depTag = cc.SharedDepTag()
deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
} else if mod.IsSanitizerEnabled(cc.Hwasan) ||
- (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64) {
+ (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64 && mctx.Os().Bionic()) {
// TODO(b/204776996): HWASan for static Rust binaries isn't supported yet.
if binary, ok := mod.compiler.(binaryInterface); ok {
if binary.staticallyLinked() {
@@ -444,28 +443,12 @@
return mod.sanitize.isSanitizerExplicitlyDisabled(t)
}
-func (mod *Module) SanitizeDep(t cc.SanitizerType) bool {
- for _, e := range mod.sanitize.Properties.SanitizeDepTypes {
- if t == e {
- return true
- }
- }
-
- return false
-}
-
func (mod *Module) SetSanitizer(t cc.SanitizerType, b bool) {
if !Bool(mod.sanitize.Properties.Sanitize.Never) {
mod.sanitize.SetSanitizer(t, b)
}
}
-func (c *Module) SetSanitizeDep(t cc.SanitizerType) {
- if !c.SanitizeDep(t) {
- c.sanitize.Properties.SanitizeDepTypes = append(c.sanitize.Properties.SanitizeDepTypes, t)
- }
-}
-
func (mod *Module) StaticallyLinked() bool {
if lib, ok := mod.compiler.(libraryInterface); ok {
return lib.rlib() || lib.static()
diff --git a/rust/source_provider.go b/rust/source_provider.go
index 7719611..4f8d22b 100644
--- a/rust/source_provider.go
+++ b/rust/source_provider.go
@@ -65,9 +65,12 @@
}
}
-func NewSourceProviderModule(hod android.HostOrDeviceSupported, sourceProvider SourceProvider, enableLints bool) *Module {
+func NewSourceProviderModule(hod android.HostOrDeviceSupported, sourceProvider SourceProvider, enableLints bool, rlibOnly bool) *Module {
_, library := NewRustLibrary(hod)
library.BuildOnlyRust()
+ if rlibOnly {
+ library.BuildOnlyRlib()
+ }
library.sourceProvider = sourceProvider
module := newModule(hod, android.MultilibBoth)
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 4773579..814bd57 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -84,6 +84,16 @@
],
}
+python_test_host {
+ name: "jsonmodify_test",
+ main: "jsonmodify_test.py",
+ srcs: [
+ "jsonmodify_test.py",
+ "jsonmodify.py",
+ ],
+ test_suites: ["general-tests"],
+}
+
python_binary_host {
name: "test_config_fixer",
main: "test_config_fixer.py",
@@ -193,3 +203,9 @@
name: "list_image",
src: "list_image.sh",
}
+
+filegroup {
+ name: "rustfmt.toml",
+ srcs: ["rustfmt.toml"],
+ visibility: ["//visibility:public"],
+}
diff --git a/scripts/jsonmodify.py b/scripts/jsonmodify.py
index ba1109e..8bd8d45 100755
--- a/scripts/jsonmodify.py
+++ b/scripts/jsonmodify.py
@@ -59,6 +59,13 @@
cur[key] = val
+class ReplaceIfEqual(str):
+ def apply(self, obj, old_val, new_val):
+ cur, key = follow_path(obj, self)
+ if cur and cur[key] == int(old_val):
+ cur[key] = new_val
+
+
class Remove(str):
def apply(self, obj):
cur, key = follow_path(obj, self)
@@ -75,6 +82,14 @@
raise ValueError(self + " should be a array.")
cur[key].extend(args)
+# A JSONDecoder that supports line comments start with //
+class JSONWithCommentsDecoder(json.JSONDecoder):
+ def __init__(self, **kw):
+ super().__init__(**kw)
+
+ def decode(self, s: str):
+ s = '\n'.join(l for l in s.split('\n') if not l.lstrip(' ').startswith('//'))
+ return super().decode(s)
def main():
parser = argparse.ArgumentParser()
@@ -91,6 +106,11 @@
help='replace value of the key specified by path. If path doesn\'t exist, no op.',
metavar=('path', 'value'),
nargs=2, dest='patch', action='append')
+ parser.add_argument("-se", "--replace-if-equal", type=ReplaceIfEqual,
+ help='replace value of the key specified by path to new_value if it\'s equal to old_value.' +
+ 'If path doesn\'t exist or the value is not equal to old_value, no op.',
+ metavar=('path', 'old_value', 'new_value'),
+ nargs=3, dest='patch', action='append')
parser.add_argument("-r", "--remove", type=Remove,
help='remove the key specified by path. If path doesn\'t exist, no op.',
metavar='path',
@@ -103,9 +123,9 @@
if args.input:
with open(args.input) as f:
- obj = json.load(f, object_pairs_hook=collections.OrderedDict)
+ obj = json.load(f, object_pairs_hook=collections.OrderedDict, cls=JSONWithCommentsDecoder)
else:
- obj = json.load(sys.stdin, object_pairs_hook=collections.OrderedDict)
+ obj = json.load(sys.stdin, object_pairs_hook=collections.OrderedDict, cls=JSONWithCommentsDecoder)
for p in args.patch:
p[0].apply(obj, *p[1:])
diff --git a/scripts/jsonmodify_test.py b/scripts/jsonmodify_test.py
new file mode 100644
index 0000000..6f0291d
--- /dev/null
+++ b/scripts/jsonmodify_test.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Tests for jsonmodify."""
+
+import json
+import jsonmodify
+import unittest
+
+
+class JsonmodifyTest(unittest.TestCase):
+
+ def test_set_value(self):
+ obj = json.loads('{"field1": 111}')
+ field1 = jsonmodify.SetValue("field1")
+ field1.apply(obj, 222)
+ field2 = jsonmodify.SetValue("field2")
+ field2.apply(obj, 333)
+ expected = json.loads('{"field1": 222, "field2": 333}')
+ self.assertEqual(obj, expected)
+
+ def test_replace(self):
+ obj = json.loads('{"field1": 111}')
+ field1 = jsonmodify.Replace("field1")
+ field1.apply(obj, 222)
+ field2 = jsonmodify.Replace("field2")
+ field2.apply(obj, 333)
+ expected = json.loads('{"field1": 222}')
+ self.assertEqual(obj, expected)
+
+ def test_replace_if_equal(self):
+ obj = json.loads('{"field1": 111, "field2": 222}')
+ field1 = jsonmodify.ReplaceIfEqual("field1")
+ field1.apply(obj, 111, 333)
+ field2 = jsonmodify.ReplaceIfEqual("field2")
+ field2.apply(obj, 444, 555)
+ field3 = jsonmodify.ReplaceIfEqual("field3")
+ field3.apply(obj, 666, 777)
+ expected = json.loads('{"field1": 333, "field2": 222}')
+ self.assertEqual(obj, expected)
+
+ def test_remove(self):
+ obj = json.loads('{"field1": 111, "field2": 222}')
+ field2 = jsonmodify.Remove("field2")
+ field2.apply(obj)
+ field3 = jsonmodify.Remove("field3")
+ field3.apply(obj)
+ expected = json.loads('{"field1": 111}')
+ self.assertEqual(obj, expected)
+
+ def test_append_list(self):
+ obj = json.loads('{"field1": [111]}')
+ field1 = jsonmodify.AppendList("field1")
+ field1.apply(obj, 222, 333)
+ field2 = jsonmodify.AppendList("field2")
+ field2.apply(obj, 444, 555, 666)
+ expected = json.loads('{"field1": [111, 222, 333], "field2": [444, 555, 666]}')
+ self.assertEqual(obj, expected)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 2d3103b..58079aa 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -39,6 +39,8 @@
parser = argparse.ArgumentParser()
parser.add_argument('--minSdkVersion', default='', dest='min_sdk_version',
help='specify minSdkVersion used by the build system')
+ parser.add_argument('--replaceMaxSdkVersionPlaceholder', default='', dest='max_sdk_version',
+ help='specify maxSdkVersion used by the build system')
parser.add_argument('--targetSdkVersion', default='', dest='target_sdk_version',
help='specify targetSdkVersion used by the build system')
parser.add_argument('--raise-min-sdk-version', dest='raise_min_sdk_version', action='store_true',
@@ -68,6 +70,8 @@
parser.add_argument('--test-only', dest='test_only', action='store_true',
help=('adds testOnly="true" attribute to application. Assign true value if application elem '
'already has a testOnly attribute.'))
+ parser.add_argument('--override-placeholder-version', dest='new_version',
+ help='Overrides the versionCode if it\'s set to the placeholder value of 0')
parser.add_argument('input', help='input AndroidManifest.xml file')
parser.add_argument('output', help='output AndroidManifest.xml file')
return parser.parse_args()
@@ -342,6 +346,37 @@
attr.value = 'true'
application.setAttributeNode(attr)
+def set_max_sdk_version(doc, max_sdk_version):
+ """Replace the maxSdkVersion attribute value for permission and
+ uses-permission tags if the value was originally set to 'current'.
+ Used for cts test cases where the maxSdkVersion should equal to
+ Build.SDK_INT.
+
+ Args:
+ doc: The XML document. May be modified by this function.
+ max_sdk_version: The requested maxSdkVersion attribute.
+ """
+ manifest = parse_manifest(doc)
+ for tag in ['permission', 'uses-permission']:
+ children = get_children_with_tag(manifest, tag)
+ for child in children:
+ max_attr = child.getAttributeNodeNS(android_ns, 'maxSdkVersion')
+ if max_attr and max_attr.value == 'current':
+ max_attr.value = max_sdk_version
+
+def override_placeholder_version(doc, new_version):
+ """Replace the versionCode attribute value if it\'s currently
+ set to the placeholder version of 0.
+
+ Args:
+ doc: The XML document. May be modified by this function.
+ new_version: The new version to set if versionCode is equal to 0.
+ """
+ manifest = parse_manifest(doc)
+ version = manifest.getAttribute("android:versionCode")
+ if (version == '0'):
+ manifest.setAttribute("android:versionCode", new_version)
+
def main():
"""Program entry point."""
try:
@@ -354,6 +389,9 @@
if args.raise_min_sdk_version:
raise_min_sdk_version(doc, args.min_sdk_version, args.target_sdk_version, args.library)
+ if args.max_sdk_version:
+ set_max_sdk_version(doc, args.max_sdk_version)
+
if args.uses_libraries:
add_uses_libraries(doc, args.uses_libraries, True)
@@ -378,6 +416,9 @@
if args.extract_native_libs is not None:
add_extract_native_libs(doc, args.extract_native_libs)
+ if args.new_version:
+ override_placeholder_version(doc, args.new_version)
+
with open(args.output, 'w') as f:
write_xml(f, doc)
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 199b279..0a62b10 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -571,5 +571,111 @@
output = self.run_test(manifest_input)
self.assert_xml_equal(output, manifest_input)
+
+class SetMaxSdkVersionTest(unittest.TestCase):
+ """Unit tests for set_max_sdk_version function."""
+
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
+ def run_test(self, input_manifest, max_sdk_version):
+ doc = minidom.parseString(input_manifest)
+ manifest_fixer.set_max_sdk_version(doc, max_sdk_version)
+ output = io.StringIO()
+ manifest_fixer.write_xml(output, doc)
+ return output.getvalue()
+
+ manifest_tmpl = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+ '%s'
+ '</manifest>\n')
+
+ def permission(self, max=None):
+ if max is None:
+ return ' <permission/>'
+ return ' <permission android:maxSdkVersion="%s"/>\n' % max
+
+ def uses_permission(self, max=None):
+ if max is None:
+ return ' <uses-permission/>'
+ return ' <uses-permission android:maxSdkVersion="%s"/>\n' % max
+
+ def test_permission_no_max_sdk_version(self):
+ """Tests if permission has no maxSdkVersion attribute"""
+ manifest_input = self.manifest_tmpl % self.permission()
+ expected = self.manifest_tmpl % self.permission()
+ output = self.run_test(manifest_input, '9000')
+ self.assert_xml_equal(output, expected)
+
+ def test_permission_max_sdk_version_changed(self):
+ """Tests if permission maxSdkVersion attribute is set to current"""
+ manifest_input = self.manifest_tmpl % self.permission('current')
+ expected = self.manifest_tmpl % self.permission(9000)
+ output = self.run_test(manifest_input, '9000')
+ self.assert_xml_equal(output, expected)
+
+ def test_permission_max_sdk_version_not_changed(self):
+ """Tests if permission maxSdkVersion attribute is not set to current"""
+ manifest_input = self.manifest_tmpl % self.permission(30)
+ expected = self.manifest_tmpl % self.permission(30)
+ output = self.run_test(manifest_input, '9000')
+ self.assert_xml_equal(output, expected)
+
+ def test_uses_permission_no_max_sdk_version(self):
+ """Tests if uses-permission has no maxSdkVersion attribute"""
+ manifest_input = self.manifest_tmpl % self.uses_permission()
+ expected = self.manifest_tmpl % self.uses_permission()
+ output = self.run_test(manifest_input, '9000')
+ self.assert_xml_equal(output, expected)
+
+ def test_uses_permission_max_sdk_version_changed(self):
+ """Tests if uses-permission maxSdkVersion attribute is set to current"""
+ manifest_input = self.manifest_tmpl % self.uses_permission('current')
+ expected = self.manifest_tmpl % self.uses_permission(9000)
+ output = self.run_test(manifest_input, '9000')
+ self.assert_xml_equal(output, expected)
+
+ def test_uses_permission_max_sdk_version_not_changed(self):
+ """Tests if uses-permission maxSdkVersion attribute is not set to current"""
+ manifest_input = self.manifest_tmpl % self.uses_permission(30)
+ expected = self.manifest_tmpl % self.uses_permission(30)
+ output = self.run_test(manifest_input, '9000')
+ self.assert_xml_equal(output, expected)
+
+class OverrideDefaultVersionTest(unittest.TestCase):
+ """Unit tests for override_default_version function."""
+
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
+ def run_test(self, input_manifest, version):
+ doc = minidom.parseString(input_manifest)
+ manifest_fixer.override_placeholder_version(doc, version)
+ output = io.StringIO()
+ manifest_fixer.write_xml(output, doc)
+ return output.getvalue()
+
+ manifest_tmpl = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android" '
+ 'android:versionCode="%s">\n'
+ '</manifest>\n')
+
+ def test_doesnt_override_existing_version(self):
+ """Tests that an existing version is not overridden"""
+ manifest_input = self.manifest_tmpl % '12345'
+ expected = manifest_input
+ output = self.run_test(manifest_input, '67890')
+ self.assert_xml_equal(output, expected)
+
+ def test_overrides_default_version(self):
+ """Tests that a default version is overridden"""
+ manifest_input = self.manifest_tmpl % '0'
+ expected = self.manifest_tmpl % '67890'
+ output = self.run_test(manifest_input, '67890')
+ self.assert_xml_equal(output, expected)
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index a60039a..13ddbe7 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -101,6 +101,9 @@
image_name: "art",
contents: ["mybootlib"],
apex_available: ["com.android.art"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
apex_key {
@@ -187,7 +190,7 @@
android.AssertStringDoesContain(t, "boot jars package check", command, expectedCommandArgs)
}
-func TestSnapshotWithBootClasspathFragment_Contents(t *testing.T) {
+func testSnapshotWithBootClasspathFragment_Contents(t *testing.T, sdk string, copyRules string) {
result := android.GroupFixturePreparers(
prepareForSdkTestWithJava,
java.PrepareForTestWithJavaDefaultModules,
@@ -199,19 +202,7 @@
// Add a platform_bootclasspath that depends on the fragment.
fixtureAddPlatformBootclasspathForBootclasspathFragment("myapex", "mybootclasspathfragment"),
- android.FixtureWithRootAndroidBp(`
- sdk {
- name: "mysdk",
- bootclasspath_fragments: ["mybootclasspathfragment"],
- java_sdk_libs: [
- // This is not strictly needed as it should be automatically added to the sdk_snapshot as
- // a java_sdk_libs module because it is used in the mybootclasspathfragment's
- // api.stub_libs property. However, it is specified here to ensure that duplicates are
- // correctly deduped.
- "mysdklibrary",
- ],
- }
-
+ android.FixtureWithRootAndroidBp(sdk+`
apex {
name: "myapex",
key: "myapex.key",
@@ -235,6 +226,9 @@
// This should be automatically added to the sdk_snapshot as a java_sdk_libs module.
stub_libs: ["mycoreplatform"],
},
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -367,24 +361,7 @@
},
}
`),
- checkAllCopyRules(`
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
-.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
-.intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
-.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
-.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
-.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
-.intermediates/mycoreplatform.stubs/android_common/javac/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
-.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
-.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
-`),
+ checkAllCopyRules(copyRules),
snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
snapshotTestChecker(checkSnapshotWithoutSource, func(t *testing.T, result *android.TestResult) {
module := result.ModuleForTests("platform-bootclasspath", "android_common")
@@ -421,6 +398,89 @@
)
}
+func TestSnapshotWithBootClasspathFragment_Contents(t *testing.T) {
+ t.Run("added-directly", func(t *testing.T) {
+ testSnapshotWithBootClasspathFragment_Contents(t, `
+ sdk {
+ name: "mysdk",
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ java_sdk_libs: [
+ // This is not strictly needed as it should be automatically added to the sdk_snapshot as
+ // a java_sdk_libs module because it is used in the mybootclasspathfragment's
+ // api.stub_libs property. However, it is specified here to ensure that duplicates are
+ // correctly deduped.
+ "mysdklibrary",
+ ],
+ }
+ `, `
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
+.intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
+.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
+.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mycoreplatform.stubs/android_common/javac/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
+.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
+.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
+`)
+ })
+
+ copyBootclasspathFragmentFromApexVariantRules := `
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
+.intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
+.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
+.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mycoreplatform.stubs/android_common/javac/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
+.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
+.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
+`
+ t.Run("added-via-apex", func(t *testing.T) {
+ testSnapshotWithBootClasspathFragment_Contents(t, `
+ sdk {
+ name: "mysdk",
+ apexes: ["myapex"],
+ }
+ `, copyBootclasspathFragmentFromApexVariantRules)
+ })
+
+ t.Run("added-directly-and-indirectly", func(t *testing.T) {
+ testSnapshotWithBootClasspathFragment_Contents(t, `
+ sdk {
+ name: "mysdk",
+ apexes: ["myapex"],
+ // This is not strictly needed as it should be automatically added to the sdk_snapshot as
+ // a bootclasspath_fragments module because it is used in the myapex's
+ // bootclasspath_fragments property. However, it is specified here to ensure that duplicates
+ // are correctly deduped.
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ java_sdk_libs: [
+ // This is not strictly needed as it should be automatically added to the sdk_snapshot as
+ // a java_sdk_libs module because it is used in the mybootclasspathfragment's
+ // api.stub_libs property. However, it is specified here to ensure that duplicates are
+ // correctly deduped.
+ "mysdklibrary",
+ ],
+ }
+ `, copyBootclasspathFragmentFromApexVariantRules)
+ })
+}
+
// TestSnapshotWithBootClasspathFragment_Fragments makes sure that the fragments property of a
// bootclasspath_fragment is correctly output to the sdk snapshot.
func TestSnapshotWithBootClasspathFragment_Fragments(t *testing.T) {
@@ -453,6 +513,9 @@
contents: [
"myotherlib",
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -482,6 +545,9 @@
module: "myotherbootclasspathfragment"
},
],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_sdk_library {
@@ -561,6 +627,9 @@
image_name: "art",
contents: ["mybootlib"],
apex_available: ["myapex"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_library {
@@ -668,6 +737,7 @@
unsupported_packages: [
"my-unsupported-packages.txt",
],
+ split_packages: ["*"],
},
}
diff --git a/sdk/build_release.go b/sdk/build_release.go
index 4c2277e..0494a28 100644
--- a/sdk/build_release.go
+++ b/sdk/build_release.go
@@ -24,18 +24,22 @@
// buildRelease represents the version of a build system used to create a specific release.
//
-// The name of the release, is the same as the code for the dessert release, e.g. S, T, etc.
+// The name of the release, is the same as the code for the dessert release, e.g. S, Tiramisu, etc.
type buildRelease struct {
- // The name of the release, e.g. S, T, etc.
+ // The name of the release, e.g. S, Tiramisu, etc.
name string
// The index of this structure within the buildReleases list.
ordinal int
}
+func (br *buildRelease) EarlierThan(other *buildRelease) bool {
+ return br.ordinal < other.ordinal
+}
+
// String returns the name of the build release.
-func (s *buildRelease) String() string {
- return s.name
+func (br *buildRelease) String() string {
+ return br.name
}
// buildReleaseSet represents a set of buildRelease objects.
diff --git a/sdk/compat_config_sdk_test.go b/sdk/compat_config_sdk_test.go
index d166add..45e8e0e 100644
--- a/sdk/compat_config_sdk_test.go
+++ b/sdk/compat_config_sdk_test.go
@@ -21,16 +21,12 @@
"android/soong/java"
)
-func TestSnapshotWithCompatConfig(t *testing.T) {
+func testSnapshotWithCompatConfig(t *testing.T, sdk string) {
result := android.GroupFixturePreparers(
prepareForSdkTestWithJava,
java.PrepareForTestWithPlatformCompatConfig,
- ).RunTestWithBp(t, `
- sdk {
- name: "mysdk",
- compat_configs: ["myconfig"],
- }
-
+ prepareForSdkTestWithApex,
+ ).RunTestWithBp(t, sdk+`
platform_compat_config {
name: "myconfig",
}
@@ -73,3 +69,28 @@
}),
)
}
+
+func TestSnapshotWithCompatConfig(t *testing.T) {
+ testSnapshotWithCompatConfig(t, `
+ sdk {
+ name: "mysdk",
+ compat_configs: ["myconfig"],
+ }
+`)
+}
+
+func TestSnapshotWithCompatConfig_Apex(t *testing.T) {
+ testSnapshotWithCompatConfig(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ min_sdk_version: "2",
+ compat_configs: ["myconfig"],
+ }
+
+ sdk {
+ name: "mysdk",
+ apexes: ["myapex"],
+ }
+`)
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index d25138f..7ab5285 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -15,6 +15,7 @@
package sdk
import (
+ "fmt"
"testing"
"android/soong/android"
@@ -257,8 +258,8 @@
android.FixtureAddFile("aidl", nil),
android.FixtureAddFile("resource.txt", nil),
).RunTestWithBp(t, `
- module_exports {
- name: "myexports",
+ sdk {
+ name: "mysdk",
java_boot_libs: ["myjavalib"],
}
@@ -278,7 +279,7 @@
}
`)
- CheckSnapshot(t, result, "myexports", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -292,11 +293,65 @@
}
`),
checkAllCopyRules(`
-.intermediates/myexports/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar
`),
)
}
+func TestSnapshotWithJavaBootLibrary_UpdatableMedia(t *testing.T) {
+ runTest := func(t *testing.T, targetBuildRelease, expectedJarPath, expectedCopyRule string) {
+ result := android.GroupFixturePreparers(
+ prepareForSdkTestWithJava,
+ android.FixtureMergeEnv(map[string]string{
+ "SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease,
+ }),
+ ).RunTestWithBp(t, `
+ sdk {
+ name: "mysdk",
+ java_boot_libs: ["updatable-media"],
+ }
+
+ java_library {
+ name: "updatable-media",
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ permitted_packages: ["pkg.media"],
+ apex_available: ["com.android.media"],
+ }
+ `)
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkAndroidBpContents(fmt.Sprintf(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "updatable-media",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["com.android.media"],
+ jars: ["%s"],
+ permitted_packages: ["pkg.media"],
+}
+`, expectedJarPath)),
+ checkAllCopyRules(expectedCopyRule),
+ )
+ }
+
+ t.Run("updatable-media in S", func(t *testing.T) {
+ runTest(t, "S", "java/updatable-media.jar", `
+.intermediates/updatable-media/android_common/package-check/updatable-media.jar -> java/updatable-media.jar
+`)
+ })
+
+ t.Run("updatable-media in T", func(t *testing.T) {
+ runTest(t, "Tiramisu", "java_boot_libs/snapshot/jars/are/invalid/updatable-media.jar", `
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/updatable-media.jar
+`)
+ })
+}
+
func TestSnapshotWithJavaSystemserverLibrary(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForSdkTestWithJava,
@@ -1284,9 +1339,9 @@
.intermediates/myjavalib.stubs.source.module_lib/android_common/metalava/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
`),
checkMergeZips(
+ ".intermediates/mysdk/common_os/tmp/sdk_library/module-lib/myjavalib_stub_sources.zip",
".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
".intermediates/mysdk/common_os/tmp/sdk_library/system/myjavalib_stub_sources.zip",
- ".intermediates/mysdk/common_os/tmp/sdk_library/module-lib/myjavalib_stub_sources.zip",
),
)
}
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index e230d5c..1ec12c3 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -473,6 +473,9 @@
name: "mybootclasspathfragment",
apex_available: ["myapex"],
contents: ["mysdklibrary"],
+ hidden_api: {
+ split_packages: ["*"],
+ },
}
java_sdk_library {
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index 01692a3..1ac405d 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -22,28 +22,21 @@
"android/soong/java"
)
-func TestSnapshotWithSystemServerClasspathFragment(t *testing.T) {
+func testSnapshotWithSystemServerClasspathFragment(t *testing.T, sdk string, targetBuildRelease string, expectedSdkSnapshot string) {
result := android.GroupFixturePreparers(
prepareForSdkTestWithJava,
java.PrepareForTestWithJavaDefaultModules,
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("mysdklibrary"),
dexpreopt.FixtureSetApexSystemServerJars("myapex:mylib", "myapex:mysdklibrary"),
+ android.FixtureModifyEnv(func(env map[string]string) {
+ if targetBuildRelease != "latest" {
+ env["SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE"] = targetBuildRelease
+ }
+ }),
prepareForSdkTestWithApex,
- android.FixtureWithRootAndroidBp(`
- sdk {
- name: "mysdk",
- systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
- java_sdk_libs: [
- // This is not strictly needed as it should be automatically added to the sdk_snapshot as
- // a java_sdk_libs module because it is used in the mysystemserverclasspathfragment's
- // contents property. However, it is specified here to ensure that duplicates are
- // correctly deduped.
- "mysdklibrary",
- ],
- }
-
+ android.FixtureWithRootAndroidBp(sdk+`
apex {
name: "myapex",
key: "myapex.key",
@@ -83,7 +76,27 @@
).RunTest(t)
CheckSnapshot(t, result, "mysdk", "",
- checkAndroidBpContents(`
+ checkAndroidBpContents(expectedSdkSnapshot),
+ )
+}
+
+func TestSnapshotWithSystemServerClasspathFragment(t *testing.T) {
+
+ commonSdk := `
+sdk {
+ name: "mysdk",
+ systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+ java_sdk_libs: [
+ // This is not strictly needed as it should be automatically added to the sdk_snapshot as
+ // a java_sdk_libs module because it is used in the mysystemserverclasspathfragment's
+ // contents property. However, it is specified here to ensure that duplicates are
+ // correctly deduped.
+ "mysdklibrary",
+ ],
+}
+ `
+
+ expectedLatestSnapshot := `
// This is auto-generated. DO NOT EDIT.
java_sdk_library_import {
@@ -120,6 +133,80 @@
"mysdklibrary",
],
}
-`),
- )
+`
+
+ t.Run("target-s", func(t *testing.T) {
+ testSnapshotWithSystemServerClasspathFragment(t, commonSdk, "S", `
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+ name: "mysdklibrary",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["myapex"],
+ shared_library: false,
+ public: {
+ jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+ stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+ current_api: "sdk_library/public/mysdklibrary.txt",
+ removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+ sdk_version: "current",
+ },
+}
+`)
+ })
+
+ t.Run("target-t", func(t *testing.T) {
+ testSnapshotWithSystemServerClasspathFragment(t, commonSdk, "Tiramisu", `
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+ name: "mysdklibrary",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["myapex"],
+ shared_library: false,
+ public: {
+ jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+ stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+ current_api: "sdk_library/public/mysdklibrary.txt",
+ removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+ sdk_version: "current",
+ },
+}
+
+java_import {
+ name: "mylib",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["myapex"],
+ jars: ["java_systemserver_libs/snapshot/jars/are/invalid/mylib.jar"],
+ permitted_packages: ["mylib"],
+}
+
+prebuilt_systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["myapex"],
+ contents: [
+ "mylib",
+ "mysdklibrary",
+ ],
+}
+`)
+ })
+
+ t.Run("added-directly", func(t *testing.T) {
+ testSnapshotWithSystemServerClasspathFragment(t, commonSdk, `latest`, expectedLatestSnapshot)
+ })
+
+ t.Run("added-via-apex", func(t *testing.T) {
+ testSnapshotWithSystemServerClasspathFragment(t, `
+ sdk {
+ name: "mysdk",
+ apexes: ["myapex"],
+ }
+ `, `latest`, expectedLatestSnapshot)
+ })
}
diff --git a/sdk/update.go b/sdk/update.go
index 457828b..c555ddc 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -108,7 +108,7 @@
mergeZips = pctx.AndroidStaticRule("SnapshotMergeZips",
blueprint.RuleParams{
- Command: `${config.MergeZipsCmd} $out $in`,
+ Command: `${config.MergeZipsCmd} -s $out $in`,
CommandDeps: []string{
"${config.MergeZipsCmd}",
},
@@ -239,7 +239,7 @@
// Finally, the member type slices are concatenated together to form a single slice. The order in
// which they are concatenated is the order in which the member types were registered in the
// android.SdkMemberTypesRegistry.
-func (s *sdk) groupMemberVariantsByMemberThenType(ctx android.ModuleContext, memberVariantDeps []sdkMemberVariantDep) []*sdkMember {
+func (s *sdk) groupMemberVariantsByMemberThenType(ctx android.ModuleContext, targetBuildRelease *buildRelease, memberVariantDeps []sdkMemberVariantDep) []*sdkMember {
byType := make(map[android.SdkMemberType][]*sdkMember)
byName := make(map[string]*sdkMember)
@@ -268,13 +268,39 @@
}
var members []*sdkMember
for _, memberListProperty := range s.memberTypeListProperties() {
- membersOfType := byType[memberListProperty.memberType]
+ memberType := memberListProperty.memberType
+
+ if !isMemberTypeSupportedByTargetBuildRelease(memberType, targetBuildRelease) {
+ continue
+ }
+
+ membersOfType := byType[memberType]
members = append(members, membersOfType...)
}
return members
}
+// isMemberTypeSupportedByTargetBuildRelease returns true if the member type is supported by the
+// target build release.
+func isMemberTypeSupportedByTargetBuildRelease(memberType android.SdkMemberType, targetBuildRelease *buildRelease) bool {
+ supportedByTargetBuildRelease := true
+ supportedBuildReleases := memberType.SupportedBuildReleases()
+ if supportedBuildReleases == "" {
+ supportedBuildReleases = "S+"
+ }
+
+ set, err := parseBuildReleaseSet(supportedBuildReleases)
+ if err != nil {
+ panic(fmt.Errorf("member type %s has invalid supported build releases %q: %s",
+ memberType.SdkPropertyName(), supportedBuildReleases, err))
+ }
+ if !set.contains(targetBuildRelease) {
+ supportedByTargetBuildRelease = false
+ }
+ return supportedByTargetBuildRelease
+}
+
func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
for _, v := range variants {
if v == newVariant {
@@ -401,12 +427,15 @@
// Group the variants for each member module together and then group the members of each member
// type together.
- members := s.groupMemberVariantsByMemberThenType(ctx, memberVariantDeps)
+ members := s.groupMemberVariantsByMemberThenType(ctx, targetBuildRelease, memberVariantDeps)
// Create the prebuilt modules for each of the member modules.
traits := s.gatherTraits()
for _, member := range members {
memberType := member.memberType
+ if !memberType.ArePrebuiltsRequired() {
+ continue
+ }
name := member.name
requiredTraits := traits[name]
@@ -452,7 +481,7 @@
// Copy the build number file into the snapshot.
builder.CopyToSnapshot(ctx.Config().BuildNumberFile(ctx), BUILD_NUMBER_FILE)
- filesToZip := builder.filesToZip
+ filesToZip := android.SortedUniquePaths(builder.filesToZip)
// zip them all
zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotFileSuffix)
@@ -488,7 +517,7 @@
Description: outputDesc,
Rule: mergeZips,
Input: zipFile,
- Inputs: builder.zipsToMerge,
+ Inputs: android.SortedUniquePaths(builder.zipsToMerge),
Output: outputZipFile,
})
}
@@ -1293,6 +1322,119 @@
}
}
+// TODO(187910671): BEGIN - Remove once modules do not have an APEX and default variant.
+// variantCoordinate contains the coordinates used to identify a variant of an SDK member.
+type variantCoordinate struct {
+ // osType identifies the OS target of a variant.
+ osType android.OsType
+ // archId identifies the architecture and whether it is for the native bridge.
+ archId archId
+ // image is the image variant name.
+ image string
+ // linkType is the link type name.
+ linkType string
+}
+
+func getVariantCoordinate(ctx *memberContext, variant android.Module) variantCoordinate {
+ linkType := ""
+ if len(ctx.MemberType().SupportedLinkages()) > 0 {
+ linkType = getLinkType(variant)
+ }
+ return variantCoordinate{
+ osType: variant.Target().Os,
+ archId: archIdFromTarget(variant.Target()),
+ image: variant.ImageVariation().Variation,
+ linkType: linkType,
+ }
+}
+
+// selectApexVariantsWhereAvailable filters the input list of variants by selecting the APEX
+// specific variant for a specific variantCoordinate when there is both an APEX and default variant.
+//
+// There is a long-standing issue where a module that is added to an APEX has both an APEX and
+// default/platform variant created even when the module does not require a platform variant. As a
+// result an indirect dependency onto a module via the APEX will use the APEX variant, whereas a
+// direct dependency onto the module will use the default/platform variant. That would result in a
+// failure while attempting to optimize the properties for a member as it would have two variants
+// when only one was expected.
+//
+// This function mitigates that problem by detecting when there are two variants that differ only
+// by apex variant, where one is the default/platform variant and one is the APEX variant. In that
+// case it picks the APEX variant. It picks the APEX variant because that is the behavior that would
+// be expected
+func selectApexVariantsWhereAvailable(ctx *memberContext, variants []android.SdkAware) []android.SdkAware {
+ moduleCtx := ctx.sdkMemberContext
+
+ // Group the variants by coordinates.
+ variantsByCoord := make(map[variantCoordinate][]android.SdkAware)
+ for _, variant := range variants {
+ coord := getVariantCoordinate(ctx, variant)
+ variantsByCoord[coord] = append(variantsByCoord[coord], variant)
+ }
+
+ toDiscard := make(map[android.SdkAware]struct{})
+ for coord, list := range variantsByCoord {
+ count := len(list)
+ if count == 1 {
+ continue
+ }
+
+ variantsByApex := make(map[string]android.SdkAware)
+ conflictDetected := false
+ for _, variant := range list {
+ apexInfo := moduleCtx.OtherModuleProvider(variant, android.ApexInfoProvider).(android.ApexInfo)
+ apexVariationName := apexInfo.ApexVariationName
+ // If there are two variants for a specific APEX variation then there is conflict.
+ if _, ok := variantsByApex[apexVariationName]; ok {
+ conflictDetected = true
+ break
+ }
+ variantsByApex[apexVariationName] = variant
+ }
+
+ // If there are more than 2 apex variations or one of the apex variations is not the
+ // default/platform variation then there is a conflict.
+ if len(variantsByApex) != 2 {
+ conflictDetected = true
+ } else if _, ok := variantsByApex[""]; !ok {
+ conflictDetected = true
+ }
+
+ // If there are no conflicts then add the default/platform variation to the list to remove.
+ if !conflictDetected {
+ toDiscard[variantsByApex[""]] = struct{}{}
+ continue
+ }
+
+ // There are duplicate variants at this coordinate and they are not the default and APEX variant
+ // so fail.
+ variantDescriptions := []string{}
+ for _, m := range list {
+ variantDescriptions = append(variantDescriptions, fmt.Sprintf(" %s", m.String()))
+ }
+
+ moduleCtx.ModuleErrorf("multiple conflicting variants detected for OsType{%s}, %s, Image{%s}, Link{%s}\n%s",
+ coord.osType, coord.archId.String(), coord.image, coord.linkType,
+ strings.Join(variantDescriptions, "\n"))
+ }
+
+ // If there are any variants to discard then remove them from the list of variants, while
+ // preserving the order.
+ if len(toDiscard) > 0 {
+ filtered := []android.SdkAware{}
+ for _, variant := range variants {
+ if _, ok := toDiscard[variant]; !ok {
+ filtered = append(filtered, variant)
+ }
+ }
+ variants = filtered
+ }
+
+ return variants
+}
+
+// TODO(187910671): END - Remove once modules do not have an APEX and default variant.
+
type baseInfo struct {
Properties android.SdkMemberProperties
}
@@ -1348,7 +1490,14 @@
if commonVariants, ok := variantsByArchId[commonArchId]; ok {
if len(osTypeVariants) != 1 {
- panic(fmt.Errorf("Expected to only have 1 variant when arch type is common but found %d", len(osTypeVariants)))
+ variants := []string{}
+ for _, m := range osTypeVariants {
+ variants = append(variants, fmt.Sprintf(" %s", m.String()))
+ }
+ panic(fmt.Errorf("expected to only have 1 variant of %q when arch type is common but found %d\n%s",
+ ctx.Name(),
+ len(osTypeVariants),
+ strings.Join(variants, "\n")))
}
// A common arch type only has one variant and its properties should be treated
@@ -1823,12 +1972,19 @@
return m.requiredTraits.Contains(trait)
}
+func (m *memberContext) IsTargetBuildBeforeTiramisu() bool {
+ return m.builder.targetBuildRelease.EarlierThan(buildReleaseT)
+}
+
+var _ android.SdkMemberContext = (*memberContext)(nil)
+
func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) {
memberType := member.memberType
// Do not add the prefer property if the member snapshot module is a source module type.
- config := ctx.sdkMemberContext.Config()
+ moduleCtx := ctx.sdkMemberContext
+ config := moduleCtx.Config()
if !memberType.UsesSourceModuleTypeInSnapshot() {
// Set the prefer based on the environment variable. This is a temporary work around to allow a
// snapshot to be created that sets prefer: true.
@@ -1853,9 +2009,10 @@
}
}
+ variants := selectApexVariantsWhereAvailable(ctx, member.variants)
+
// Group the variants by os type.
variantsByOsType := make(map[android.OsType][]android.Module)
- variants := member.Variants()
for _, variant := range variants {
osType := variant.Target().Os
variantsByOsType[osType] = append(variantsByOsType[osType], variant)
@@ -1901,7 +2058,7 @@
}
// Extract properties which are common across all architectures and os types.
- extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
+ extractCommonProperties(moduleCtx, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
// Add the common properties to the module.
addSdkMemberPropertiesToSet(ctx, commonProperties, bpModule)
diff --git a/tests/androidmk_test.sh b/tests/androidmk_test.sh
index 331dc77..d0d382b 100755
--- a/tests/androidmk_test.sh
+++ b/tests/androidmk_test.sh
@@ -5,7 +5,7 @@
# How to run: bash path-to-script/androidmk_test.sh
# Tests of converting license functionality of the androidmk tool
REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
-$REAL_TOP/build/soong/soong_ui.bash --make-mode androidmk
+"$REAL_TOP/build/soong/soong_ui.bash" --make-mode androidmk
source "$(dirname "$0")/lib.sh"
@@ -113,11 +113,14 @@
run_androidmk_test "a/b/c/d/Android.mk" "a/b/c/d/Android.bp"
}
-run_androidmk_test () {
+function run_androidmk_test {
export ANDROID_BUILD_TOP="$MOCK_TOP"
-
- local out=$($REAL_TOP/*/host/*/bin/androidmk "$1")
- local expected=$(<"$2")
+ local -r androidmk=("$REAL_TOP"/*/host/*/bin/androidmk)
+ if [[ ${#androidmk[@]} -ne 1 ]]; then
+ fail "Multiple androidmk binaries found: ${androidmk[*]}"
+ fi
+ local -r out=$("${androidmk[0]}" "$1")
+ local -r expected=$(<"$2")
if [[ "$out" != "$expected" ]]; then
ANDROID_BUILD_TOP="$REAL_TOP"
diff --git a/tests/apex_comparison_tests.sh b/tests/apex_comparison_tests.sh
new file mode 100755
index 0000000..4b2f795
--- /dev/null
+++ b/tests/apex_comparison_tests.sh
@@ -0,0 +1,115 @@
+#!/bin/bash
+
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -euo pipefail
+
+# Soong/Bazel integration test for building unbundled apexes in the real source tree.
+#
+# These tests build artifacts from head and compares their contents.
+
+if [ ! -e "build/make/core/Makefile" ]; then
+ echo "$0 must be run from the top of the Android source tree."
+ exit 1
+fi
+
+############
+# Test Setup
+############
+
+OUTPUT_DIR="$(mktemp -d)"
+SOONG_OUTPUT_DIR="$OUTPUT_DIR/soong"
+BAZEL_OUTPUT_DIR="$OUTPUT_DIR/bazel"
+
+function cleanup {
+ # call bazel clean because some bazel outputs don't have w bits.
+ call_bazel clean
+ rm -rf "${OUTPUT_DIR}"
+}
+trap cleanup EXIT
+
+###########
+# Run Soong
+###########
+export UNBUNDLED_BUILD_SDKS_FROM_SOURCE=true # don't rely on prebuilts
+export TARGET_BUILD_APPS="com.android.adbd com.android.tzdata build.bazel.examples.apex.minimal"
+packages/modules/common/build/build_unbundled_mainline_module.sh \
+ --product module_arm \
+ --dist_dir "$SOONG_OUTPUT_DIR"
+
+######################
+# Run bp2build / Bazel
+######################
+build/soong/soong_ui.bash --make-mode BP2BUILD_VERBOSE=1 --skip-soong-tests bp2build
+
+function call_bazel() {
+ tools/bazel --output_base="$BAZEL_OUTPUT_DIR" $@
+}
+BAZEL_OUT="$(call_bazel info output_path)"
+
+call_bazel build --config=bp2build --config=ci --config=android_arm \
+ //packages/modules/adb/apex:com.android.adbd \
+ //system/timezone/apex:com.android.tzdata \
+ //build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal.apex
+
+# Build debugfs separately, as it's not a dep of apexer, but needs to be an explicit arg.
+call_bazel build --config=bp2build --config=linux_x86_64 //external/e2fsprogs/debugfs
+DEBUGFS_PATH="$BAZEL_OUT/linux_x86_64-fastbuild/bin/external/e2fsprogs/debugfs/debugfs"
+
+function run_deapexer() {
+ call_bazel run --config=bp2build --config=linux_x86_64 //system/apex/tools:deapexer \
+ -- \
+ --debugfs_path="$DEBUGFS_PATH" \
+ $@
+}
+
+#######
+# Tests
+#######
+
+function compare_deapexer_list() {
+ local APEX_DIR=$1; shift
+ local APEX=$1; shift
+
+ # Compare the outputs of `deapexer list`, which lists the contents of the apex filesystem image.
+ local SOONG_APEX="$SOONG_OUTPUT_DIR/$APEX"
+ local BAZEL_APEX="$BAZEL_OUT/android_arm-fastbuild/bin/$APEX_DIR/$APEX"
+
+ local SOONG_LIST="$OUTPUT_DIR/soong.list"
+ local BAZEL_LIST="$OUTPUT_DIR/bazel.list"
+
+ run_deapexer list "$SOONG_APEX" > "$SOONG_LIST"
+ run_deapexer list "$BAZEL_APEX" > "$BAZEL_LIST"
+
+ if cmp -s "$SOONG_LIST" "$BAZEL_LIST"
+ then
+ echo "ok: $APEX"
+ else
+ echo "contents of $APEX are different between Soong and Bazel:"
+ echo
+ echo expected
+ echo
+ cat "$SOONG_LIST"
+ echo
+ echo got
+ echo
+ cat "$BAZEL_LIST"
+ exit 1
+ fi
+}
+
+compare_deapexer_list packages/modules/adb/apex com.android.adbd.apex
+compare_deapexer_list system/timezone/apex com.android.tzdata.apex
+compare_deapexer_list build/bazel/examples/apex/minimal build.bazel.examples.apex.minimal.apex
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 78ddced..3cdf6aa 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -11,10 +11,10 @@
function test_bp2build_null_build() {
setup
run_soong bp2build
- local output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+ local -r output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
run_soong bp2build
- local output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+ local -r output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
if [[ "$output_mtime1" != "$output_mtime2" ]]; then
fail "Output bp2build marker file changed on null build"
@@ -36,10 +36,10 @@
touch foo/bar/a.txt foo/bar/b.txt
run_soong bp2build
- local output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+ local -r output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
run_soong bp2build
- local output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+ local -r output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
if [[ "$output_mtime1" != "$output_mtime2" ]]; then
fail "Output bp2build marker file changed on null build"
@@ -147,10 +147,10 @@
run_soong bp2build
run_bazel build --package_path=out/soong/workspace //a:qq
- local output_mtime1=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
+ local -r output_mtime1=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
run_bazel build --package_path=out/soong/workspace //a:qq
- local output_mtime2=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
+ local -r output_mtime2=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
if [[ "$output_mtime1" != "$output_mtime2" ]]; then
fail "output changed on null build"
@@ -161,7 +161,7 @@
EOF
run_bazel build --package_path=out/soong/workspace //a:qq
- local output_mtime3=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
+ local -r output_mtime3=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
if [[ "$output_mtime1" == "$output_mtime3" ]]; then
fail "output not changed when included header changed"
diff --git a/tests/lib.sh b/tests/lib.sh
index abe84d3..6210e77 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -8,7 +8,7 @@
REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
-if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
+if [[ -n "$HARDWIRED_MOCK_TOP" ]]; then
MOCK_TOP="$HARDWIRED_MOCK_TOP"
else
MOCK_TOP=$(mktemp -t -d st.XXXXX)
@@ -36,37 +36,38 @@
}
function info {
- echo -e "\e[92;1m[TEST HARNESS INFO]\e[0m" $*
+ echo -e "\e[92;1m[TEST HARNESS INFO]\e[0m" "$*"
}
function fail {
- echo -e "\e[91;1mFAILED:\e[0m" $*
+ echo -e "\e[91;1mFAILED:\e[0m" "$*"
exit 1
}
-function copy_directory() {
+function copy_directory {
local dir="$1"
- local parent="$(dirname "$dir")"
+ local -r parent="$(dirname "$dir")"
mkdir -p "$MOCK_TOP/$parent"
cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
}
-function symlink_file() {
+function symlink_file {
local file="$1"
mkdir -p "$MOCK_TOP/$(dirname "$file")"
ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
}
-function symlink_directory() {
+function symlink_directory {
local dir="$1"
mkdir -p "$MOCK_TOP/$dir"
# We need to symlink the contents of the directory individually instead of
# using one symlink for the whole directory because finder.go doesn't follow
# symlinks when looking for Android.bp files
- for i in $(ls "$REAL_TOP/$dir"); do
+ for i in "$REAL_TOP/$dir"/*; do
+ i=$(basename "$i")
local target="$MOCK_TOP/$dir/$i"
local source="$REAL_TOP/$dir/$i"
@@ -96,7 +97,7 @@
touch "$MOCK_TOP/Android.bp"
}
-function setup() {
+function setup {
cleanup_mock_top
mkdir -p "$MOCK_TOP"
@@ -108,12 +109,14 @@
tar xzf "$WARMED_UP_MOCK_TOP"
}
-function run_soong() {
- build/soong/soong_ui.bash --make-mode --skip-ninja --skip-config --soong-only --skip-soong-tests "$@"
+# shellcheck disable=SC2120
+function run_soong {
+ USE_RBE=false build/soong/soong_ui.bash --make-mode --skip-ninja --skip-config --soong-only --skip-soong-tests "$@"
}
-function create_mock_bazel() {
+function create_mock_bazel {
copy_directory build/bazel
+ copy_directory build/bazel_common_rules
symlink_directory prebuilts/bazel
symlink_directory prebuilts/clang
@@ -126,7 +129,7 @@
symlink_file tools/bazel
}
-run_bazel() {
+function run_bazel {
# Remove the ninja_build output marker file to communicate to buildbot that this is not a regular Ninja build, and its
# output should not be parsed as such.
rm -rf out/ninja_build
@@ -134,11 +137,11 @@
tools/bazel "$@"
}
-run_ninja() {
+function run_ninja {
build/soong/soong_ui.bash --make-mode --skip-config --soong-only --skip-soong-tests "$@"
}
-info "Starting Soong integration test suite $(basename $0)"
+info "Starting Soong integration test suite $(basename "$0")"
info "Mock top: $MOCK_TOP"
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 76a918b..1e07727 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -9,3 +9,7 @@
"$TOP/build/soong/tests/bp2build_bazel_test.sh"
"$TOP/build/soong/tests/soong_test.sh"
"$TOP/build/bazel/ci/rbc_regression_test.sh" aosp_arm64-userdebug
+
+# The following tests build against the full source tree and don't rely on the
+# mock client.
+"$TOP/build/soong/tests/apex_comparison_tests.sh"
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 3dc87f5..cfcf804 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -34,15 +34,16 @@
deps: [
"blueprint",
"blueprint-bootstrap",
+ "blueprint-microfactory",
+ "soong-finder",
+ "soong-remoteexec",
+ "soong-shared",
"soong-ui-build-paths",
"soong-ui-logger",
"soong-ui-metrics",
"soong-ui-status",
"soong-ui-terminal",
"soong-ui-tracer",
- "soong-shared",
- "soong-finder",
- "blueprint-microfactory",
],
srcs: [
"bazel.go",
diff --git a/ui/build/build.go b/ui/build/build.go
index aadf4af..f7a2d7b 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -183,8 +183,8 @@
}
}
-// Build the tree. The 'what' argument can be used to chose which components of
-// the build to run, via checking various bitmasks.
+// Build the tree. Various flags in `config` govern which components of
+// the build to run.
func Build(ctx Context, config Config) {
ctx.Verboseln("Starting build with args:", config.Arguments())
ctx.Verboseln("Environment:", config.Environment().Environ())
@@ -201,7 +201,20 @@
buildLock := BecomeSingletonOrFail(ctx, config)
defer buildLock.Unlock()
+ logArgsOtherThan := func(specialTargets ...string) {
+ var ignored []string
+ for _, a := range config.Arguments() {
+ if !inList(a, specialTargets) {
+ ignored = append(ignored, a)
+ }
+ }
+ if len(ignored) > 0 {
+ ctx.Printf("ignoring arguments %q", ignored)
+ }
+ }
+
if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {
+ logArgsOtherThan("clean", "clobber")
clean(ctx, config)
return
}
@@ -266,6 +279,7 @@
}
if config.StartRBE() {
+ cleanupRBELogsDir(ctx, config)
startRBE(ctx, config)
defer DumpRBEMetrics(ctx, config, filepath.Join(config.LogsDir(), "rbe_metrics.pb"))
}
@@ -278,6 +292,7 @@
if inList("installclean", config.Arguments()) ||
inList("install-clean", config.Arguments()) {
+ logArgsOtherThan("installclean", "install-clean")
installClean(ctx, config)
ctx.Println("Deleted images and staging directories.")
return
@@ -285,6 +300,7 @@
if inList("dataclean", config.Arguments()) ||
inList("data-clean", config.Arguments()) {
+ logArgsOtherThan("dataclean", "data-clean")
dataClean(ctx, config)
ctx.Println("Deleted data files.")
return
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 1c80cff..fd60177 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -167,6 +167,7 @@
productOut("debug_ramdisk"),
productOut("vendor_ramdisk"),
productOut("vendor_debug_ramdisk"),
+ productOut("vendor_kernel_ramdisk"),
productOut("test_harness_ramdisk"),
productOut("recovery"),
productOut("root"),
diff --git a/ui/build/config.go b/ui/build/config.go
index 0092ff1..cbf1986 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -19,12 +19,14 @@
"encoding/json"
"fmt"
"io/ioutil"
+ "math/rand"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
+ "syscall"
"time"
"android/soong/shared"
@@ -42,6 +44,15 @@
envConfigFetchTimeout = 10 * time.Second
)
+var (
+ rbeRandPrefix int
+)
+
+func init() {
+ rand.Seed(time.Now().UnixNano())
+ rbeRandPrefix = rand.Intn(1000)
+}
+
type Config struct{ *configImpl }
type configImpl struct {
@@ -145,10 +156,15 @@
// experiments system to control Soong features dynamically.
func fetchEnvConfig(ctx Context, config *configImpl, envConfigName string) error {
configName := envConfigName + "." + jsonSuffix
- expConfigFetcher := &smpb.ExpConfigFetcher{}
+ expConfigFetcher := &smpb.ExpConfigFetcher{Filename: &configName}
defer func() {
ctx.Metrics.ExpConfigFetcher(expConfigFetcher)
}()
+ if !config.GoogleProdCredsExist() {
+ status := smpb.ExpConfigFetcher_MISSING_GCERT
+ expConfigFetcher.Status = &status
+ return nil
+ }
s, err := os.Stat(configFetcher)
if err != nil {
@@ -200,7 +216,7 @@
}
if err := fetchEnvConfig(ctx, config, bc); err != nil {
- fmt.Fprintf(os.Stderr, "Failed to fetch config file: %v\n", err)
+ ctx.Verbosef("Failed to fetch config file: %v\n", err)
}
configDirs := []string{
@@ -1144,34 +1160,25 @@
return true
}
-func (c *configImpl) rbeLogDir() string {
- for _, f := range []string{"RBE_log_dir", "FLAG_log_dir"} {
+func (c *configImpl) rbeProxyLogsDir() string {
+ for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} {
if v, ok := c.environ.Get(f); ok {
return v
}
}
- if c.Dist() {
- return c.LogsDir()
- }
- return c.OutDir()
+ buildTmpDir := shared.TempDirForOutDir(c.SoongOutDir())
+ return filepath.Join(buildTmpDir, "rbe")
}
-func (c *configImpl) rbeStatsOutputDir() string {
- for _, f := range []string{"RBE_output_dir", "FLAG_output_dir"} {
- if v, ok := c.environ.Get(f); ok {
- return v
+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.
+ for _, f := range []string{"RBE_proxy_log_dir", "FLAG_output_dir"} {
+ if _, ok := c.environ.Get(f); ok {
+ return false
}
}
- return c.rbeLogDir()
-}
-
-func (c *configImpl) rbeLogPath() string {
- for _, f := range []string{"RBE_log_path", "FLAG_log_path"} {
- if v, ok := c.environ.Get(f); ok {
- return v
- }
- }
- return fmt.Sprintf("text://%v/reproxy_log.txt", c.rbeLogDir())
+ return true
}
func (c *configImpl) rbeExecRoot() string {
@@ -1223,6 +1230,25 @@
return "RBE_use_application_default_credentials", "true"
}
+func (c *configImpl) rbeSockAddr(dir string) (string, error) {
+ maxNameLen := len(syscall.RawSockaddrUnix{}.Path)
+ base := fmt.Sprintf("reproxy_%v.sock", rbeRandPrefix)
+
+ name := filepath.Join(dir, base)
+ if len(name) < maxNameLen {
+ return name, nil
+ }
+
+ name = filepath.Join("/tmp", base)
+ if len(name) < maxNameLen {
+ return name, nil
+ }
+
+ return "", fmt.Errorf("cannot generate a proxy socket address shorter than the limit of %v", maxNameLen)
+}
+
+// IsGooglerEnvironment returns true if the current build is running
+// on a Google developer machine and false otherwise.
func (c *configImpl) IsGooglerEnvironment() bool {
cf := "ANDROID_BUILD_ENVIRONMENT_CONFIG"
if v, ok := c.environ.Get(cf); ok {
@@ -1231,6 +1257,8 @@
return false
}
+// GoogleProdCredsExist determine whether credentials exist on the
+// Googler machine to use remote execution.
func (c *configImpl) GoogleProdCredsExist() bool {
if _, err := exec.Command("/usr/bin/prodcertstatus", "--simple_output", "--nocheck_loas").Output(); err != nil {
return false
@@ -1238,10 +1266,21 @@
return true
}
+// UseRemoteBuild indicates whether to use a remote build acceleration system
+// to speed up the build.
func (c *configImpl) UseRemoteBuild() bool {
return c.UseGoma() || c.UseRBE()
}
+// StubbyExists checks whether the stubby binary exists on the machine running
+// the build.
+func (c *configImpl) StubbyExists() bool {
+ if _, err := exec.LookPath("stubby"); err != nil {
+ return false
+ }
+ return true
+}
+
// RemoteParallel controls how many remote jobs (i.e., commands which contain
// gomacc) are run in parallel. Note the parallelism of all other jobs is
// still limited by Parallel()
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 78d37b4..6231e52 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -16,13 +16,12 @@
import (
"fmt"
- "math/rand"
"os"
"path/filepath"
"runtime"
- "syscall"
- "time"
+ "strings"
+ "android/soong/remoteexec"
"android/soong/ui/metrics"
)
@@ -54,34 +53,17 @@
return cmdPath
}
-func sockAddr(dir string) (string, error) {
- maxNameLen := len(syscall.RawSockaddrUnix{}.Path)
- rand.Seed(time.Now().UnixNano())
- base := fmt.Sprintf("reproxy_%v.sock", rand.Intn(1000))
-
- name := filepath.Join(dir, base)
- if len(name) < maxNameLen {
- return name, nil
- }
-
- name = filepath.Join("/tmp", base)
- if len(name) < maxNameLen {
- return name, nil
- }
-
- return "", fmt.Errorf("cannot generate a proxy socket address shorter than the limit of %v", maxNameLen)
-}
-
func getRBEVars(ctx Context, config Config) map[string]string {
vars := map[string]string{
- "RBE_log_path": config.rbeLogPath(),
- "RBE_log_dir": config.rbeLogDir(),
- "RBE_re_proxy": config.rbeReproxy(),
- "RBE_exec_root": config.rbeExecRoot(),
- "RBE_output_dir": config.rbeStatsOutputDir(),
+ "RBE_log_dir": config.rbeProxyLogsDir(),
+ "RBE_re_proxy": config.rbeReproxy(),
+ "RBE_exec_root": config.rbeExecRoot(),
+ "RBE_output_dir": config.rbeProxyLogsDir(),
+ "RBE_proxy_log_dir": config.rbeProxyLogsDir(),
+ "RBE_platform": "container-image=" + remoteexec.DefaultImage,
}
if config.StartRBE() {
- name, err := sockAddr(absPath(ctx, config.TempDir()))
+ name, err := config.rbeSockAddr(absPath(ctx, config.TempDir()))
if err != nil {
ctx.Fatalf("Error retrieving socket address: %v", err)
return nil
@@ -100,6 +82,17 @@
return vars
}
+func cleanupRBELogsDir(ctx Context, config Config) {
+ if !config.shouldCleanupRBELogsDir() {
+ return
+ }
+
+ rbeTmpDir := config.rbeProxyLogsDir()
+ if err := os.RemoveAll(rbeTmpDir); err != nil {
+ fmt.Fprintln(ctx.Writer, "\033[33mUnable to remove RBE log directory: ", err, "\033[0m")
+ }
+}
+
func startRBE(ctx Context, config Config) {
ctx.BeginTrace(metrics.RunSetupTool, "rbe_bootstrap")
defer ctx.EndTrace()
@@ -110,6 +103,11 @@
if n := ulimitOrFatal(ctx, config, "-n"); n < rbeLeastNFiles {
ctx.Fatalf("max open files is insufficient: %d; want >= %d.\n", n, rbeLeastNFiles)
}
+ if _, err := os.Stat(config.rbeProxyLogsDir()); os.IsNotExist(err) {
+ if err := os.MkdirAll(config.rbeProxyLogsDir(), 0744); err != nil {
+ ctx.Fatalf("Unable to create logs dir (%v) for RBE: %v", config.rbeProxyLogsDir, err)
+ }
+ }
cmd := Command(ctx, config, "startRBE bootstrap", rbeCommand(ctx, config, bootstrapCmd))
@@ -119,7 +117,6 @@
}
func stopRBE(ctx Context, config Config) {
- defer checkProdCreds(ctx, config)
cmd := Command(ctx, config, "stopRBE bootstrap", rbeCommand(ctx, config, bootstrapCmd), "-shutdown")
output, err := cmd.CombinedOutput()
if err != nil {
@@ -132,12 +129,31 @@
}
}
-func checkProdCreds(ctx Context, config Config) {
- if !config.IsGooglerEnvironment() || config.GoogleProdCredsExist() {
+func prodCredsAuthType(config Config) bool {
+ authVar, val := config.rbeAuth()
+ if strings.Contains(authVar, "use_google_prod_creds") && val != "" && val != "false" {
+ return true
+ }
+ return false
+}
+
+// Check whether proper auth exists for RBE builds run within a
+// Google dev environment.
+func CheckProdCreds(ctx Context, config Config) {
+ if !config.IsGooglerEnvironment() {
+ return
+ }
+ if !config.StubbyExists() && prodCredsAuthType(config) {
+ fmt.Fprintln(ctx.Writer, "")
+ fmt.Fprintln(ctx.Writer, fmt.Sprintf("\033[33mWARNING: %q binary not found in $PATH, follow go/build-fast#opting-out-of-loas-credentials instead for authenticating with RBE.\033[0m", "stubby"))
+ fmt.Fprintln(ctx.Writer, "")
+ return
+ }
+ if config.GoogleProdCredsExist() {
return
}
fmt.Fprintln(ctx.Writer, "")
- fmt.Fprintln(ctx.Writer, "\033[33mWARNING: Missing LOAS credentials, please run `gcert`. This will result in failing RBE builds in the future, see go/build-fast#authentication.\033[0m")
+ fmt.Fprintln(ctx.Writer, "\033[33mWARNING: Missing LOAS credentials, please run `gcert`. This will result in failing builds in the future, see go/rbe-android-default-announcement.\033[0m")
fmt.Fprintln(ctx.Writer, "")
}
@@ -161,7 +177,7 @@
return
}
- outputDir := config.rbeStatsOutputDir()
+ outputDir := config.rbeProxyLogsDir()
if outputDir == "" {
ctx.Fatal("RBE output dir variable not defined. Aborting metrics dumping.")
}
diff --git a/ui/build/rbe_test.go b/ui/build/rbe_test.go
index 8ff96bc..266f76b 100644
--- a/ui/build/rbe_test.go
+++ b/ui/build/rbe_test.go
@@ -56,7 +56,8 @@
env := Environment(tt.env)
env.Set("OUT_DIR", tmpDir)
env.Set("RBE_DIR", tmpDir)
- env.Set("RBE_output_dir", t.TempDir())
+ env.Set("RBE_output_dir", tmpDir)
+ env.Set("RBE_proxy_log_dir", tmpDir)
config := Config{&configImpl{
environ: &env,
}}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 8992b4f..29c3b65 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -312,14 +312,6 @@
fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
)
- globFiles := []string{
- config.NamedGlobFile(soongBuildTag),
- config.NamedGlobFile(bp2buildTag),
- config.NamedGlobFile(jsonModuleGraphTag),
- config.NamedGlobFile(queryviewTag),
- config.NamedGlobFile(soongDocsTag),
- }
-
// The glob .ninja files are subninja'd. However, they are generated during
// the build itself so we write an empty file if the file does not exist yet
// so that the subninja doesn't fail on clean builds
@@ -342,7 +334,7 @@
runGoTests: !config.skipSoongTests,
// If we want to debug soong_build, we need to compile it for debugging
debugCompilation: os.Getenv("SOONG_DELVE") != "",
- subninjas: globFiles,
+ subninjas: bootstrapGlobFileList(config),
primaryBuilderInvocations: []bootstrap.PrimaryBuilderInvocation{
mainSoongBuildInvocation,
bp2buildInvocation,
@@ -544,7 +536,7 @@
buf, err := os.ReadFile(soongBuildMetricsFile)
if errors.Is(err, fs.ErrNotExist) {
// Soong may not have run during this invocation
- ctx.Verbosef("Failed to read metrics file, %s: %s", soongBuildMetricsFile, err)
+ ctx.Verbosef("Failed to read metrics file, %s: %s", soongBuildMetricsFile, err)
return nil
} else if err != nil {
ctx.Fatalf("Failed to load %s: %s", soongBuildMetricsFile, err)
diff --git a/ui/metrics/bp2build_progress_metrics_proto/BUILD.bazel b/ui/metrics/bp2build_progress_metrics_proto/BUILD.bazel
new file mode 100644
index 0000000..356b188
--- /dev/null
+++ b/ui/metrics/bp2build_progress_metrics_proto/BUILD.bazel
@@ -0,0 +1,27 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load("//build/bazel/rules/python:py_proto.bzl", "py_proto_library")
+
+proto_library(
+ name = "bp2build_proto",
+ srcs = ["bp2build.proto"],
+ strip_import_prefix = "",
+)
+
+py_proto_library(
+ name = "bp2build_py_proto",
+ deps = [":bp2build_proto"],
+ visibility = ["//build/bazel/scripts/bp2build-progress:__pkg__"],
+)
diff --git a/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto b/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto
new file mode 100644
index 0000000..4aee88b
--- /dev/null
+++ b/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package bp2build_proto;
+
+
+// Conversion progress report for root_modules .
+message Bp2buildConversionProgress {
+
+ // Soong module identifying information.
+ message Module {
+ // Name of the Soong module.
+ string name = 1;
+
+ // Directory that the Soong module is in.
+ string directory = 2;
+
+ // Module type of this module.
+ string type = 3;
+
+ // All unconverted transitive dependencies.
+ repeated string unconverted_deps = 4;
+
+ // Total number of transitive dependencies.
+ int32 num_deps = 5;
+ }
+
+ // Modules that the transitive dependencies were identified for.
+ repeated string root_modules = 1;
+
+ // Names of all dependencies of the root_modules.
+ int32 num_deps = 2;
+
+ // Module with all its unconverted transitive dependencies.
+ repeated Module unconverted = 3;
+}
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index 4bc713b..2dd8299 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -220,9 +220,10 @@
type ExpConfigFetcher_ConfigStatus int32
const (
- ExpConfigFetcher_NO_CONFIG ExpConfigFetcher_ConfigStatus = 0
- ExpConfigFetcher_CONFIG ExpConfigFetcher_ConfigStatus = 1
- ExpConfigFetcher_ERROR ExpConfigFetcher_ConfigStatus = 2
+ ExpConfigFetcher_NO_CONFIG ExpConfigFetcher_ConfigStatus = 0
+ ExpConfigFetcher_CONFIG ExpConfigFetcher_ConfigStatus = 1
+ ExpConfigFetcher_ERROR ExpConfigFetcher_ConfigStatus = 2
+ ExpConfigFetcher_MISSING_GCERT ExpConfigFetcher_ConfigStatus = 3
)
// Enum value maps for ExpConfigFetcher_ConfigStatus.
@@ -231,11 +232,13 @@
0: "NO_CONFIG",
1: "CONFIG",
2: "ERROR",
+ 3: "MISSING_GCERT",
}
ExpConfigFetcher_ConfigStatus_value = map[string]int32{
- "NO_CONFIG": 0,
- "CONFIG": 1,
- "ERROR": 2,
+ "NO_CONFIG": 0,
+ "CONFIG": 1,
+ "ERROR": 2,
+ "MISSING_GCERT": 3,
}
)
@@ -1578,7 +1581,7 @@
0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72,
0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73,
- 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xc8, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66,
+ 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61,
0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
@@ -1587,22 +1590,23 @@
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d,
0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
- 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x34, 0x0a, 0x0c, 0x43, 0x6f, 0x6e,
+ 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f,
0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46,
- 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x22,
- 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49,
- 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69,
- 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
- 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42,
- 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
- 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c,
- 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
- 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42,
- 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75,
- 0x6c, 0x65, 0x73, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73,
- 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f,
- 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12,
+ 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54,
+ 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c,
+ 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f,
+ 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f,
+ 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78,
+ 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f,
+ 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62,
+ 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f,
+ 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78,
+ 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d,
+ 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+ 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
}
var (
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 51dd523..4f8fe7f 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -251,6 +251,7 @@
NO_CONFIG = 0;
CONFIG = 1;
ERROR = 2;
+ MISSING_GCERT = 3;
}
// The result of the call to expconfigfetcher
// NO_CONFIG - Not part of experiment
diff --git a/ui/terminal/simple_status.go b/ui/terminal/simple_status.go
index 3157813..9e9ffc0 100644
--- a/ui/terminal/simple_status.go
+++ b/ui/terminal/simple_status.go
@@ -22,41 +22,36 @@
)
type simpleStatusOutput struct {
- writer io.Writer
- formatter formatter
- keepANSI bool
- outputLevel status.MsgLevel
+ writer io.Writer
+ formatter formatter
+ keepANSI bool
}
// NewSimpleStatusOutput returns a StatusOutput that represents the
// current build status similarly to Ninja's built-in terminal
// output.
-func NewSimpleStatusOutput(w io.Writer, formatter formatter, keepANSI bool, quietBuild bool) status.StatusOutput {
- level := status.StatusLvl
- if quietBuild {
- level = status.PrintLvl
- }
+func NewSimpleStatusOutput(w io.Writer, formatter formatter, keepANSI bool) status.StatusOutput {
return &simpleStatusOutput{
- writer: w,
- formatter: formatter,
- keepANSI: keepANSI,
- outputLevel: level,
+ writer: w,
+ formatter: formatter,
+ keepANSI: keepANSI,
}
}
func (s *simpleStatusOutput) Message(level status.MsgLevel, message string) {
- if level >= s.outputLevel {
- fmt.Fprintln(s.writer, s.formatter.message(level, message))
+ if level >= status.StatusLvl {
+ output := s.formatter.message(level, message)
+ if !s.keepANSI {
+ output = string(stripAnsiEscapes([]byte(output)))
+ }
+ fmt.Fprintln(s.writer, output)
}
}
-func (s *simpleStatusOutput) StartAction(_ *status.Action, _ status.Counts) {
+func (s *simpleStatusOutput) StartAction(action *status.Action, counts status.Counts) {
}
func (s *simpleStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
- if s.outputLevel > status.StatusLvl {
- return
- }
str := result.Description
if str == "" {
str = result.Command
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index ff0af47..2ad174f 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -29,9 +29,9 @@
func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild, forceKeepANSI bool) status.StatusOutput {
formatter := newFormatter(statusFormat, quietBuild)
- if forceSimpleOutput || quietBuild || !isSmartTerminal(w) {
- return NewSimpleStatusOutput(w, formatter, forceKeepANSI, quietBuild)
- } else {
+ if !forceSimpleOutput && isSmartTerminal(w) {
return NewSmartStatusOutput(w, formatter)
+ } else {
+ return NewSimpleStatusOutput(w, formatter, forceKeepANSI)
}
}
diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go
index 810e31d..b9057d2 100644
--- a/ui/terminal/status_test.go
+++ b/ui/terminal/status_test.go
@@ -81,9 +81,9 @@
},
{
name: "action with output with ansi codes",
- calls: actionWithOuptutWithAnsiCodes,
- smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n",
- simple: "[100% 1/1] action1\ncolor\n",
+ calls: actionWithOutputWithAnsiCodes,
+ smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n\x1b[31mcolor message\x1b[0m\n",
+ simple: "[100% 1/1] action1\ncolor\ncolor message\n",
},
}
@@ -257,12 +257,14 @@
runner.finishAction(result1)
}
-func actionWithOuptutWithAnsiCodes(stat status.StatusOutput) {
+func actionWithOutputWithAnsiCodes(stat status.StatusOutput) {
result1WithOutputWithAnsiCodes := status.ActionResult{Action: action1, Output: "\x1b[31mcolor\x1b[0m"}
runner := newRunner(stat, 1)
runner.startAction(action1)
runner.finishAction(result1WithOutputWithAnsiCodes)
+
+ stat.Message(status.PrintLvl, "\x1b[31mcolor message\x1b[0m")
}
func TestSmartStatusOutputWidthChange(t *testing.T) {
diff --git a/zip/zip.go b/zip/zip.go
index ae379f5..955fe68 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -201,6 +201,16 @@
return fmt.Sprintf("path %q is outside relative root %q", x.Path, x.RelativeRoot)
}
+type ConflictingFileError struct {
+ Dest string
+ Prev string
+ Src string
+}
+
+func (x ConflictingFileError) Error() string {
+ return fmt.Sprintf("destination %q has two files %q and %q", x.Dest, x.Prev, x.Src)
+}
+
type ZipWriter struct {
time time.Time
createdFiles map[string]string
@@ -605,13 +615,24 @@
if prev, exists := z.createdDirs[dest]; exists {
return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
}
+
+ return nil
+ }
+
+ checkDuplicateFiles := func(dest, src string) (bool, error) {
if prev, exists := z.createdFiles[dest]; exists {
- return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
+ if prev != src {
+ return true, ConflictingFileError{
+ Dest: dest,
+ Prev: prev,
+ Src: src,
+ }
+ }
+ return true, nil
}
z.createdFiles[dest] = src
-
- return nil
+ return false, nil
}
if s.IsDir() {
@@ -625,6 +646,14 @@
return err
}
+ duplicate, err := checkDuplicateFiles(dest, src)
+ if err != nil {
+ return err
+ }
+ if duplicate {
+ return nil
+ }
+
return z.writeSymlink(dest, src)
} else if s.Mode().IsRegular() {
r, err := z.fs.Open(src)
@@ -667,6 +696,14 @@
return err
}
+ duplicate, err := checkDuplicateFiles(dest, src)
+ if err != nil {
+ return err
+ }
+ if duplicate {
+ return nil
+ }
+
return z.writeFileContents(header, r)
} else {
return fmt.Errorf("%s is not a file, directory, or symlink", src)
@@ -678,7 +715,14 @@
return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
}
if prev, exists := z.createdFiles[dest]; exists {
- return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
+ if prev != src {
+ return ConflictingFileError{
+ Dest: dest,
+ Prev: prev,
+ Src: src,
+ }
+ }
+ return nil
}
if err := z.writeDirectory(filepath.Dir(dest), src, true); err != nil {
diff --git a/zip/zip_test.go b/zip/zip_test.go
index 79cc0b4..c4832dc 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -46,6 +46,7 @@
"dangling -> missing": nil,
"a/a/d -> b": nil,
"c": fileC,
+ "d/a/a": nil,
"l_nl": []byte("a/a/a\na/a/b\nc\n\\[\n"),
"l_sp": []byte("a/a/a a/a/b c \\["),
"l2": []byte("missing\n"),
@@ -400,6 +401,17 @@
fh("a/a/b", fileB, zip.Deflate),
},
},
+ {
+ name: "duplicate sources",
+ args: fileArgsBuilder().
+ File("a/a/a").
+ File("a/a/a"),
+ compressionLevel: 9,
+
+ files: []zip.FileHeader{
+ fh("a/a/a", fileA, zip.Deflate),
+ },
+ },
// errors
{
@@ -427,6 +439,15 @@
File("a/a/a"),
err: IncorrectRelativeRootError{},
},
+ {
+ name: "error conflicting file",
+ args: fileArgsBuilder().
+ SourcePrefixToStrip("a").
+ File("a/a/a").
+ SourcePrefixToStrip("d").
+ File("d/a/a"),
+ err: ConflictingFileError{},
+ },
}
for _, test := range testCases {
@@ -454,13 +475,17 @@
t.Fatalf("want error %v, got %v", test.err, err)
} else if test.err != nil {
if os.IsNotExist(test.err) {
- if !os.IsNotExist(test.err) {
+ if !os.IsNotExist(err) {
t.Fatalf("want error %v, got %v", test.err, err)
}
} else if _, wantRelativeRootErr := test.err.(IncorrectRelativeRootError); wantRelativeRootErr {
if _, gotRelativeRootErr := err.(IncorrectRelativeRootError); !gotRelativeRootErr {
t.Fatalf("want error %v, got %v", test.err, err)
}
+ } else if _, wantConflictingFileError := test.err.(ConflictingFileError); wantConflictingFileError {
+ if _, gotConflictingFileError := err.(ConflictingFileError); !gotConflictingFileError {
+ t.Fatalf("want error %v, got %v", test.err, err)
+ }
} else {
t.Fatalf("want error %v, got %v", test.err, err)
}