diff --git a/.bazelrc b/.bazelrc index 53485cb9743..4d371cf3512 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1 +1,3 @@ build --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 + +common:skip_android --deleted_packages=binder diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 8793cfb82fe..e2b54da1725 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -100,10 +100,10 @@ jobs: key: ${{ runner.os }}-bazel-${{ env.USE_BAZEL_VERSION }}-${{ hashFiles('WORKSPACE', 'repositories.bzl') }} - name: Run bazel build - run: bazelisk build //... --enable_bzlmod=${{ matrix.bzlmod }} --enable_workspace=${{ !matrix.bzlmod }} + run: bazelisk build //... --config=skip_android --enable_bzlmod=${{ matrix.bzlmod }} --enable_workspace=${{ !matrix.bzlmod }} - name: Run bazel test - run: bazelisk test //... --enable_bzlmod=${{ matrix.bzlmod }} --enable_workspace=${{ !matrix.bzlmod }} + run: bazelisk test //... --config=skip_android --enable_bzlmod=${{ matrix.bzlmod }} --enable_workspace=${{ !matrix.bzlmod }} - name: Run example bazel build run: bazelisk build //... --enable_bzlmod=${{ matrix.bzlmod }} --enable_workspace=${{ !matrix.bzlmod }} diff --git a/COMPILING.md b/COMPILING.md index b7df1319beb..02c06515127 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -28,6 +28,23 @@ project, run: $ ./gradlew publishToMavenLocal ``` +### Building with Bazel + +grpc-java can also be built using Bazel, like so: + +```sh +$ bazelisk build //... +``` + +Some parts of grpc-java depend on Android. Bazel can build these parts too but, +for size, licensing and maintenance reasons, it requires a locally installed +Android SDK. If you don't have the SDK and/or don't care about Android, use the +`skip_android` configuration to skip building the Android parts: + +```sh +$ bazelisk build //... --config=skip_android +``` + ### Notes for IntelliJ Building in IntelliJ works best when you import the project as a Gradle project and delegate IDE build/run actions to Gradle. diff --git a/MODULE.bazel b/MODULE.bazel index 50fd1f95d34..dc826993a8c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -46,16 +46,31 @@ IO_GRPC_GRPC_JAVA_ARTIFACTS = [ ] # GRPC_DEPS_END +ANDROID_ARTIFACTS = [ + "androidx.annotation:annotation:1.6.0", + "androidx.annotation:annotation-jvm:1.6.0", + "androidx.core:core:1.13.1", + "androidx.lifecycle:lifecycle-common:2.6.2", +] + bazel_dep(name = "abseil-cpp", version = "20250512.1") bazel_dep(name = "bazel_jar_jar", version = "0.1.11.bcr.1") bazel_dep(name = "bazel_skylib", version = "1.7.1") bazel_dep(name = "googleapis", version = "0.0.0-20240326-1c8d509c5", repo_name = "com_google_googleapis") bazel_dep(name = "grpc-proto", version = "0.0.0-20240627-ec30f58.bcr.1", repo_name = "io_grpc_grpc_proto") bazel_dep(name = "protobuf", version = "33.4", repo_name = "com_google_protobuf") +bazel_dep(name = "rules_android", version = "0.7.2") bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "rules_java", version = "9.1.0") bazel_dep(name = "rules_jvm_external", version = "6.0") +android_sdk_repository_extension = use_extension( + "@rules_android//rules/android_sdk_repository:rule.bzl", + "android_sdk_repository_extension", +) +use_repo(android_sdk_repository_extension, "androidsdk") +register_toolchains("@androidsdk//:sdk-toolchain", "@androidsdk//:all") + maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") maven.install( artifacts = IO_GRPC_GRPC_JAVA_ARTIFACTS, @@ -64,7 +79,32 @@ maven.install( ], strict_visibility = True, ) -use_repo(maven, "maven") + +# We isolate Android-specific deps in this separate repo ('grpc_android_maven') instead of the one +# above (having default name 'maven'). +# +# Under bzlmod, rules_jvm_external merges all contributions to the same named repository (like the +# default 'maven' repo) across the entire dependency graph. If we put Android dependencies there, +# then *every* downstream consumer's merged 'maven' repository would include these Android +# artifacts. +# +# Because merged repositories are resolved using only the root module's (the consumer's) +# repository list, any consumer without 'maven.google.com' configured in their root module +# would fail to resolve these artifacts, breaking their build even if they don't use Android. +# +# By using a distinct name ('grpc_android_maven'), we prevent merging. This repository is resolved +# independently, allowing it to use grpc-java's own repository config (which includes +# maven.google.com) without affecting downstream consumers' default 'maven' repo. +maven.install( + name = "grpc_android_maven", + artifacts = ANDROID_ARTIFACTS, + repositories = [ + "https://repo.maven.apache.org/maven2/", + "https://maven.google.com", # for androidx.* + ], + strict_visibility = True, +) +use_repo(maven, "maven", "grpc_android_maven") maven.override( coordinates = "com.google.protobuf:protobuf-java", @@ -158,3 +198,7 @@ maven.override( coordinates = "io.grpc:grpc-util", target = "@io_grpc_grpc_java//util", ) +maven.override( + coordinates = "io.grpc:grpc-binder", + target = "@io_grpc_grpc_java//binder", +) diff --git a/binder/BUILD.bazel b/binder/BUILD.bazel new file mode 100644 index 00000000000..2f2872f9ac2 --- /dev/null +++ b/binder/BUILD.bazel @@ -0,0 +1,27 @@ +load("@rules_android//rules:rules.bzl", "android_library") +load("@rules_jvm_external//:defs.bzl", "artifact") + +licenses(["notice"]) + +android_library( + name = "binder", + srcs = glob([ + "src/main/java/**/*.java", + ]), + manifest = "src/main/AndroidManifest.xml", + custom_package = "io.grpc.binder", + visibility = ["//visibility:public"], + exports = ["@grpc_android_maven//:androidx_annotation_annotation"], + deps = [ + "//api", + "//core:internal", + # Resolve android deps from the isolated grpc_android_maven repository. + "@grpc_android_maven//:androidx_annotation_annotation", + "@grpc_android_maven//:androidx_annotation_annotation_jvm", + "@grpc_android_maven//:androidx_core_core", + "@grpc_android_maven//:androidx_lifecycle_lifecycle_common", + artifact("com.google.code.findbugs:jsr305"), + artifact("com.google.errorprone:error_prone_annotations"), + artifact("com.google.guava:guava"), + ], +)