Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Give Kotlin jars an OSGi Manifest #18812

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions build_defs/kotlin_opts.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Protobuf-specific kotlin build rules."""

load("//:protobuf_version.bzl", "PROTOBUF_JAVA_VERSION")
load("//java/osgi:osgi.bzl", "osgi_kt_jvm_library")


BUNDLE_DOC_URL = "https://developers.google.com/protocol-buffers/"
BUNDLE_LICENSE = "https://opensource.org/licenses/BSD-3-Clause"

def protobuf_versioned_kt_jvm_library(
automatic_module_name,
bundle_description,
bundle_name,
bundle_symbolic_name,
bundle_additional_imports = [],
bundle_additional_exports = [],
**kwargs):
"""Extends `kt_jvm_library` to add OSGi headers to the MANIFEST.MF using bndlib

This macro should be usable as a drop-in replacement for kt_jvm_library.

The additional arguments are given the bndlib tool to generate an OSGi-compliant manifest file.
See [bnd documentation](https://bnd.bndtools.org/chapters/110-introduction.html)

Takes all the args that are standard for a kt_jvm_library target plus the following.
Args:
bundle_description: (required) The Bundle-Description header defines a short
description of this bundle.
automatic_module_name: (required) The Automatic-Module-Name header that represents
the name of the module when this bundle is used as an automatic
module.
bundle_name: (required) The Bundle-Name header defines a readable name for this
bundle. This should be a short, human-readable name that can
contain spaces.
bundle_symbolic_name: (required) The Bundle-SymbolicName header specifies a
non-localizable name for this bundle. The bundle symbolic name
together with a version must identify a unique bundle though it can
be installed multiple times in a framework. The bundle symbolic
name should be based on the reverse domain name convention.
bundle_additional_exports: The Export-Package header contains a
declaration of exported packages. These are additional export
package statements to be added before the default wildcard export
"*;version={$Bundle-Version}".
bundle_additional_imports: The Import-Package header declares the
imported packages for this bundle. These are additional import
package statements to be added before the default wildcard import
"*".
**kwargs: Additional key-word arguments that are passed to the internal
kt_jvm_library target.
"""
osgi_kt_jvm_library(
automatic_module_name = automatic_module_name,
bundle_doc_url = BUNDLE_DOC_URL,
bundle_license = BUNDLE_LICENSE,
bundle_version = PROTOBUF_JAVA_VERSION,
bundle_description = bundle_description,
bundle_name = bundle_name,
bundle_symbolic_name = bundle_symbolic_name,
bundle_additional_exports = bundle_additional_exports,
bundle_additional_imports = bundle_additional_imports + ["sun.misc;resolution:=optional"],
**kwargs
)
25 changes: 20 additions & 5 deletions java/kotlin-lite/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix")
load("//:protobuf.bzl", "internal_gen_kt_protos")
load("//:protobuf_version.bzl", "PROTOBUF_JAVA_VERSION")
load("//bazel:java_lite_proto_library.bzl", "java_lite_proto_library")
load("//build_defs:kotlin_opts.bzl", "protobuf_versioned_kt_jvm_library")

java_lite_proto_library(
name = "example_extensible_message_java_proto_lite",
Expand Down Expand Up @@ -47,6 +48,24 @@ kt_jvm_library(
],
)

protobuf_versioned_kt_jvm_library(
name = "kotlin-lite_bundle",
automatic_module_name = "com.google.protobuf",
bundle_description = "Kotlin lite Protocol Buffers library. Protocol " +
"Buffers are a way of encoding structured data in " +
"an efficient yet extensible format.",
bundle_name = "Protocol Buffers [Kotlin-Lite]",
bundle_symbolic_name = "com.google.protobuf",
visibility = ["//visibility:public"],
exports = [
":lite_extensions",
":well_known_protos_kotlin_lite",
"//java/kotlin:bytestring_lib",
"//java/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
"//java/kotlin:shared_runtime",
],
)

kt_jvm_export(
name = "kotlin-lite_mvn",
deploy_env = [
Expand All @@ -62,11 +81,7 @@ kt_jvm_export(
],
tags = ["manual"],
runtime_deps = [
":lite_extensions",
":well_known_protos_kotlin_lite",
"//java/kotlin:bytestring_lib",
"//java/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
"//java/kotlin:shared_runtime",
":kotlin-lite_bundle",
],
)

Expand Down
25 changes: 20 additions & 5 deletions java/kotlin/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ load("//:protobuf.bzl", "internal_gen_kt_protos")
load("//:protobuf_version.bzl", "PROTOBUF_JAVA_VERSION")
load("//bazel:java_proto_library.bzl", "java_proto_library")
load("//bazel:proto_library.bzl", "proto_library")
load("//build_defs:kotlin_opts.bzl", "protobuf_versioned_kt_jvm_library")

exports_files([
"src/test/kotlin/com/google/protobuf/Proto3Test.kt",
Expand Down Expand Up @@ -50,6 +51,24 @@ kt_jvm_library(
deps = ["//java/core"],
)

protobuf_versioned_kt_jvm_library(
name = "kotlin_bundle",
automatic_module_name = "com.google.protobuf",
bundle_description = "Kotlin core Protocol Buffers library. Protocol " +
"Buffers are a way of encoding structured data in an" +
"efficient yet extensible format.",
bundle_name = "Protocol Buffers [Kotlin-Core]",
bundle_symbolic_name = "com.google.protobuf",
visibility = ["//visibility:public"],
exports = [
":bytestring_lib",
":full_extensions",
":only_for_use_in_proto_generated_code_its_generator_and_tests",
":shared_runtime",
":well_known_protos_kotlin",
]
)

kt_jvm_export(
name = "kotlin_mvn",
deploy_env = [
Expand All @@ -65,11 +84,7 @@ kt_jvm_export(
],
tags = ["manual"],
runtime_deps = [
":bytestring_lib",
":full_extensions",
":only_for_use_in_proto_generated_code_its_generator_and_tests",
":shared_runtime",
":well_known_protos_kotlin",
":kotlin_bundle",
],
)

Expand Down
131 changes: 131 additions & 0 deletions java/osgi/osgi.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
""" Custom rule to generate OSGi Manifest """

load("@rules_java//java:defs.bzl", "JavaInfo", "java_library")
load("@rules_kotlin//kotlin/internal:defs.bzl", "KtJvmInfo")
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")

# Note that this rule is currently agnostic of protobuf concerns and could be
# pulled out as a general purpose helper to allow migrations from maven to bazel
Expand Down Expand Up @@ -138,6 +140,64 @@ def osgi_java_library(
visibility = visibility,
)

def osgi_kt_jvm_library(
name,
automatic_module_name,
bundle_description,
bundle_doc_url,
bundle_license,
bundle_name,
bundle_symbolic_name,
bundle_version,
bundle_additional_imports = [],
bundle_additional_exports = [],
deps = [],
exports = [],
exported_plugins = [],
neverlink = False,
runtime_deps = [],
visibility = [],
**kwargs):
"""Extends `kt_jvm_library` to add OSGi headers to the MANIFEST.MF using bndlib

This macro should be usable as a drop-in replacement for kt_jvm_library.

The additional arguments are the same as osgi_java_library above.
"""

# Build the private jar without the OSGI manifest
private_library_name = "%s-no-manifest-do-not-use" % name
kt_jvm_library(
name = private_library_name,
deps = deps,
runtime_deps = runtime_deps,
neverlink = True,
visibility = ["//visibility:private"],
**kwargs
)

# Repackage the jar with an OSGI manifest
_osgi_kt_jvm_jar(
name = name,
automatic_module_name = automatic_module_name,
bundle_description = bundle_description,
bundle_doc_url = bundle_doc_url,
bundle_license = bundle_license,
bundle_name = bundle_name,
bundle_symbolic_name = bundle_symbolic_name,
bundle_version = bundle_version,
export_package = bundle_additional_exports + ["*;version=${Bundle-Version}"],
import_package = bundle_additional_imports + ["*"],
target = private_library_name,
deps = deps,
runtime_deps = runtime_deps,
exported_plugins = exported_plugins,
neverlink = neverlink,
exports = exports,
visibility = visibility,
)


def _run_osgi_wrapper(ctx, input_jar, classpath_jars, output_jar):
args = ctx.actions.args()
args.add_joined("--classpath", classpath_jars, join_with = ":")
Expand All @@ -162,6 +222,7 @@ def _run_osgi_wrapper(ctx, input_jar, classpath_jars, output_jar):
progress_message = "Generating OSGi bundle Manifest for %s" % input_jar.path,
)


def _osgi_jar_impl(ctx):
if len(ctx.attr.target[JavaInfo].java_outputs) != 1:
fail("osgi_jar rule can only be used on a single java target.")
Expand Down Expand Up @@ -242,3 +303,73 @@ _osgi_jar = rule(
),
},
)


# Kotlin implementation of osgi jar, removes classpath and source_jar
def _osgi_kt_jvm_jar_impl(ctx):
if len(ctx.attr.target[JavaInfo].java_outputs) != 1:
fail("osgi_jar rule can only be used on a single java target.")
target_java_output = ctx.attr.target[JavaInfo].java_outputs[0]

output_jar = ctx.outputs.output_jar

input_jar = target_java_output.class_jar

_run_osgi_wrapper(ctx, input_jar, [], output_jar)

return [
DefaultInfo(
files = depset([output_jar]),
# Workaround for https://github.com/bazelbuild/bazel/issues/15043
# Bazel's native rule such as sh_test do not pick up 'files' in
# DefaultInfo for a target in 'data'.
data_runfiles = ctx.runfiles([output_jar]),
),
JavaInfo(
output_jar = output_jar,

# compile_jar should be an ijar, but using an ijar results in
# missing protobuf import version.
compile_jar = output_jar,
generated_class_jar = target_java_output.generated_class_jar,
native_headers_jar = target_java_output.native_headers_jar,
manifest_proto = target_java_output.manifest_proto,
neverlink = ctx.attr.neverlink,
deps = [dep[JavaInfo] for dep in ctx.attr.deps],
runtime_deps = [dep[JavaInfo] for dep in ctx.attr.runtime_deps],
exports = [exp[JavaInfo] for exp in ctx.attr.exports],
exported_plugins = ctx.attr.exported_plugins,
),
]


_osgi_kt_jvm_jar = rule(
implementation = _osgi_kt_jvm_jar_impl,
outputs = {
"output_jar": "lib%{name}.jar",
},
attrs = {
"automatic_module_name": attr.string(),
"bundle_copyright": attr.string(),
"bundle_description": attr.string(),
"bundle_doc_url": attr.string(),
"bundle_license": attr.string(),
"bundle_name": attr.string(),
"bundle_version": attr.string(),
"bundle_symbolic_name": attr.string(),
"export_package": attr.string_list(),
"import_package": attr.string_list(),
"target": attr.label(),
"deps": attr.label_list(),
"runtime_deps": attr.label_list(),
"exports": attr.label_list(),
"neverlink": attr.bool(),
"exported_plugins": attr.label_list(),
"_osgi_wrapper_exe": attr.label(
executable = True,
cfg = "exec",
allow_files = True,
default = Label("//java/osgi:osgi_wrapper"),
),
},
)
Loading