Skip to content

Commit 27ddb9c

Browse files
deannagarciacopybara-github
authored andcommitted
Give Kotlin jars an OSGi Manifest (protocolbuffers#18812)
Extend our Java OSGi library to have a version that works for Kotlin. Add a `protobuf_versioned_kt_jvm_library` that creates a bundle with the OSGi manifest and call that instead of `kt_jvm_library` for all our kotlin maven release targets. Closes protocolbuffers#18812 COPYBARA_INTEGRATE_REVIEW=protocolbuffers#18812 from deannagarcia:kotlinOSGi 81bab06 PiperOrigin-RevId: 686220820
1 parent 082cf00 commit 27ddb9c

File tree

4 files changed

+316
-10
lines changed

4 files changed

+316
-10
lines changed

build_defs/kotlin_opts.bzl

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""Protobuf-specific kotlin build rules."""
2+
3+
load("//:protobuf_version.bzl", "PROTOBUF_JAVA_VERSION")
4+
load("//java/osgi:kotlin_osgi.bzl", "osgi_kt_jvm_library")
5+
6+
BUNDLE_DOC_URL = "https://developers.google.com/protocol-buffers/"
7+
BUNDLE_LICENSE = "https://opensource.org/licenses/BSD-3-Clause"
8+
9+
def protobuf_versioned_kt_jvm_library(
10+
automatic_module_name,
11+
bundle_description,
12+
bundle_name,
13+
bundle_symbolic_name,
14+
bundle_additional_imports = [],
15+
bundle_additional_exports = [],
16+
**kwargs):
17+
"""Extends `kt_jvm_library` to add OSGi headers to the MANIFEST.MF using bndlib
18+
19+
This macro should be usable as a drop-in replacement for kt_jvm_library.
20+
21+
The additional arguments are given the bndlib tool to generate an OSGi-compliant manifest file.
22+
See [bnd documentation](https://bnd.bndtools.org/chapters/110-introduction.html)
23+
24+
Takes all the args that are standard for a kt_jvm_library target plus the following.
25+
Args:
26+
bundle_description: (required) The Bundle-Description header defines a short
27+
description of this bundle.
28+
automatic_module_name: (required) The Automatic-Module-Name header that represents
29+
the name of the module when this bundle is used as an automatic
30+
module.
31+
bundle_name: (required) The Bundle-Name header defines a readable name for this
32+
bundle. This should be a short, human-readable name that can
33+
contain spaces.
34+
bundle_symbolic_name: (required) The Bundle-SymbolicName header specifies a
35+
non-localizable name for this bundle. The bundle symbolic name
36+
together with a version must identify a unique bundle though it can
37+
be installed multiple times in a framework. The bundle symbolic
38+
name should be based on the reverse domain name convention.
39+
bundle_additional_exports: The Export-Package header contains a
40+
declaration of exported packages. These are additional export
41+
package statements to be added before the default wildcard export
42+
"*;version={$Bundle-Version}".
43+
bundle_additional_imports: The Import-Package header declares the
44+
imported packages for this bundle. These are additional import
45+
package statements to be added before the default wildcard import
46+
"*".
47+
**kwargs: Additional key-word arguments that are passed to the internal
48+
kt_jvm_library target.
49+
"""
50+
osgi_kt_jvm_library(
51+
automatic_module_name = automatic_module_name,
52+
bundle_doc_url = BUNDLE_DOC_URL,
53+
bundle_license = BUNDLE_LICENSE,
54+
bundle_version = PROTOBUF_JAVA_VERSION,
55+
bundle_description = bundle_description,
56+
bundle_name = bundle_name,
57+
bundle_symbolic_name = bundle_symbolic_name,
58+
bundle_additional_exports = bundle_additional_exports,
59+
bundle_additional_imports = bundle_additional_imports + ["sun.misc;resolution:=optional"],
60+
**kwargs
61+
)

java/kotlin-lite/BUILD.bazel

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix")
44
load("//:protobuf.bzl", "internal_gen_kt_protos")
55
load("//:protobuf_version.bzl", "PROTOBUF_JAVA_VERSION")
66
load("//bazel:java_lite_proto_library.bzl", "java_lite_proto_library")
7+
load("//build_defs:kotlin_opts.bzl", "protobuf_versioned_kt_jvm_library")
78

89
java_lite_proto_library(
910
name = "example_extensible_message_java_proto_lite",
@@ -47,6 +48,24 @@ kt_jvm_library(
4748
],
4849
)
4950

51+
protobuf_versioned_kt_jvm_library(
52+
name = "kotlin-lite_bundle",
53+
automatic_module_name = "com.google.protobuf",
54+
bundle_description = "Kotlin lite Protocol Buffers library. Protocol " +
55+
"Buffers are a way of encoding structured data in " +
56+
"an efficient yet extensible format.",
57+
bundle_name = "Protocol Buffers [Kotlin-Lite]",
58+
bundle_symbolic_name = "com.google.protobuf",
59+
visibility = ["//visibility:public"],
60+
exports = [
61+
":lite_extensions",
62+
":well_known_protos_kotlin_lite",
63+
"//java/kotlin:bytestring_lib",
64+
"//java/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
65+
"//java/kotlin:shared_runtime",
66+
],
67+
)
68+
5069
kt_jvm_export(
5170
name = "kotlin-lite_mvn",
5271
deploy_env = [
@@ -62,11 +81,7 @@ kt_jvm_export(
6281
],
6382
tags = ["manual"],
6483
runtime_deps = [
65-
":lite_extensions",
66-
":well_known_protos_kotlin_lite",
67-
"//java/kotlin:bytestring_lib",
68-
"//java/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
69-
"//java/kotlin:shared_runtime",
84+
":kotlin-lite_bundle",
7085
],
7186
)
7287

java/kotlin/BUILD.bazel

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ load("//:protobuf.bzl", "internal_gen_kt_protos")
55
load("//:protobuf_version.bzl", "PROTOBUF_JAVA_VERSION")
66
load("//bazel:java_proto_library.bzl", "java_proto_library")
77
load("//bazel:proto_library.bzl", "proto_library")
8+
load("//build_defs:kotlin_opts.bzl", "protobuf_versioned_kt_jvm_library")
89

910
exports_files([
1011
"src/test/kotlin/com/google/protobuf/Proto3Test.kt",
@@ -50,6 +51,24 @@ kt_jvm_library(
5051
deps = ["//java/core"],
5152
)
5253

54+
protobuf_versioned_kt_jvm_library(
55+
name = "kotlin_bundle",
56+
automatic_module_name = "com.google.protobuf",
57+
bundle_description = "Kotlin core Protocol Buffers library. Protocol " +
58+
"Buffers are a way of encoding structured data in an" +
59+
"efficient yet extensible format.",
60+
bundle_name = "Protocol Buffers [Kotlin-Core]",
61+
bundle_symbolic_name = "com.google.protobuf",
62+
visibility = ["//visibility:public"],
63+
exports = [
64+
":bytestring_lib",
65+
":full_extensions",
66+
":only_for_use_in_proto_generated_code_its_generator_and_tests",
67+
":shared_runtime",
68+
":well_known_protos_kotlin",
69+
],
70+
)
71+
5372
kt_jvm_export(
5473
name = "kotlin_mvn",
5574
deploy_env = [
@@ -65,11 +84,7 @@ kt_jvm_export(
6584
],
6685
tags = ["manual"],
6786
runtime_deps = [
68-
":bytestring_lib",
69-
":full_extensions",
70-
":only_for_use_in_proto_generated_code_its_generator_and_tests",
71-
":shared_runtime",
72-
":well_known_protos_kotlin",
87+
":kotlin_bundle",
7388
],
7489
)
7590

java/osgi/kotlin_osgi.bzl

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
""" Custom rule to generate OSGi Manifest for Kotlin """
2+
3+
load("@rules_java//java:defs.bzl", "JavaInfo")
4+
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
5+
6+
def osgi_kt_jvm_library(
7+
name,
8+
automatic_module_name,
9+
bundle_description,
10+
bundle_doc_url,
11+
bundle_license,
12+
bundle_name,
13+
bundle_symbolic_name,
14+
bundle_version,
15+
bundle_additional_imports = [],
16+
bundle_additional_exports = [],
17+
deps = [],
18+
exports = [],
19+
exported_plugins = [],
20+
neverlink = False,
21+
runtime_deps = [],
22+
visibility = [],
23+
**kwargs):
24+
"""Extends `kt_jvm_library` to add OSGi headers to the MANIFEST.MF using bndlib
25+
26+
This macro should be usable as a drop-in replacement for kt_jvm_library.
27+
28+
The additional arguments are given the bndlib tool to generate an OSGi-compliant manifest file.
29+
See [bnd documentation](https://bnd.bndtools.org/chapters/110-introduction.html)
30+
31+
Args:
32+
name: (required) A unique name for this target.
33+
automatic_module_name: (required) The Automatic-Module-Name header that represents
34+
the name of the module when this bundle is used as an automatic
35+
module.
36+
bundle_description: (required) The Bundle-Description header defines a short
37+
description of this bundle.
38+
bundle_doc_url: (required) The Bundle-DocURL headers must contain a URL pointing
39+
to documentation about this bundle.
40+
bundle_license: (required) The Bundle-License header provides an optional machine
41+
readable form of license information.
42+
bundle_name: (required) The Bundle-Name header defines a readable name for this
43+
bundle. This should be a short, human-readable name that can
44+
contain spaces.
45+
bundle_symbolic_name: (required) The Bundle-SymbolicName header specifies a
46+
non-localizable name for this bundle. The bundle symbolic name
47+
together with a version must identify a unique bundle though it can
48+
be installed multiple times in a framework. The bundle symbolic
49+
name should be based on the reverse domain name convention.
50+
bundle_version: (required) The Bundle-Version header specifies the version string
51+
for this bundle. The version string is expected to follow semantic
52+
versioning conventions MAJOR.MINOR.PATCH[.BUILD]
53+
bundle_additional_exports: The Export-Package header contains a
54+
declaration of exported packages. These are additional export
55+
package statements to be added before the default wildcard export
56+
"*;version={$Bundle-Version}".
57+
bundle_additional_imports: The Import-Package header declares the
58+
imported packages for this bundle. These are additional import
59+
package statements to be added before the default wildcard import
60+
"*".
61+
deps: The list of libraries to link into this library. See general
62+
comments about deps at Typical attributes defined by most build
63+
rules. The jars built by java_library rules listed in deps will be
64+
on the compile-time classpath of this rule. Furthermore the
65+
transitive closure of their deps, runtime_deps and exports will be
66+
on the runtime classpath. By contrast, targets in the data
67+
attribute are included in the runfiles but on neither the
68+
compile-time nor runtime classpath.
69+
exports: Exported libraries.
70+
exported_plugins: The list of java_plugins (e.g. annotation processors)
71+
to export to libraries that directly depend on this library. The
72+
specified list of java_plugins will be applied to any library which
73+
directly depends on this library, just as if that library had
74+
explicitly declared these labels in plugins.
75+
neverlink: Whether this library should only be used for compilation and
76+
not at runtime. Useful if the library will be provided by the runtime
77+
environment during execution. Examples of such libraries are the IDE
78+
APIs for IDE plug-ins or tools.jar for anything running on a standard
79+
JDK.
80+
runtime_deps: Libraries to make available to the final binary or test
81+
at runtime only. Like ordinary deps, these will appear on the runtime
82+
classpath, but unlike them, not on the compile-time classpath.
83+
Dependencies needed only at runtime should be listed here.
84+
Dependency-analysis tools should ignore targets that appear in both
85+
runtime_deps and deps
86+
visibility: The visibility attribute on a target controls whether the
87+
target can be used in other packages. See the documentation for
88+
visibility.
89+
**kwargs: Additional key-word arguments that are passed to the internal
90+
java_library target.
91+
92+
"""
93+
94+
# Build the private jar without the OSGI manifest
95+
private_library_name = "%s-no-manifest-do-not-use" % name
96+
kt_jvm_library(
97+
name = private_library_name,
98+
deps = deps,
99+
runtime_deps = runtime_deps,
100+
neverlink = True,
101+
visibility = ["//visibility:private"],
102+
**kwargs
103+
)
104+
105+
# Repackage the jar with an OSGI manifest
106+
_osgi_kt_jvm_jar(
107+
name = name,
108+
automatic_module_name = automatic_module_name,
109+
bundle_description = bundle_description,
110+
bundle_doc_url = bundle_doc_url,
111+
bundle_license = bundle_license,
112+
bundle_name = bundle_name,
113+
bundle_symbolic_name = bundle_symbolic_name,
114+
bundle_version = bundle_version,
115+
export_package = bundle_additional_exports + ["*;version=${Bundle-Version}"],
116+
import_package = bundle_additional_imports + ["*"],
117+
target = private_library_name,
118+
deps = deps,
119+
runtime_deps = runtime_deps,
120+
exported_plugins = exported_plugins,
121+
neverlink = neverlink,
122+
exports = exports,
123+
visibility = visibility,
124+
)
125+
126+
def _run_osgi_wrapper(ctx, input_jar, output_jar):
127+
args = ctx.actions.args()
128+
args.add("--input_jar", input_jar.path)
129+
args.add("--output_jar", output_jar.path)
130+
args.add("--automatic_module_name", ctx.attr.automatic_module_name)
131+
args.add("--bundle_copyright", ctx.attr.bundle_copyright)
132+
args.add("--bundle_description", ctx.attr.bundle_description)
133+
args.add("--bundle_doc_url", ctx.attr.bundle_doc_url)
134+
args.add("--bundle_license", ctx.attr.bundle_license)
135+
args.add("--bundle_name", ctx.attr.bundle_name)
136+
args.add("--bundle_version", ctx.attr.bundle_version)
137+
args.add("--bundle_symbolic_name", ctx.attr.bundle_symbolic_name)
138+
args.add_joined("--export_package", ctx.attr.export_package, join_with = ",")
139+
args.add_joined("--import_package", ctx.attr.import_package, join_with = ",")
140+
141+
ctx.actions.run(
142+
inputs = [input_jar],
143+
executable = ctx.executable._osgi_wrapper_exe,
144+
arguments = [args],
145+
outputs = [output_jar],
146+
progress_message = "Generating OSGi bundle Manifest for %s" % input_jar.path,
147+
)
148+
149+
# Kotlin implementation of osgi jar, removes classpath and source_jar
150+
def _osgi_kt_jvm_jar_impl(ctx):
151+
if len(ctx.attr.target[JavaInfo].java_outputs) != 1:
152+
fail("osgi_jar rule can only be used on a single java target.")
153+
target_java_output = ctx.attr.target[JavaInfo].java_outputs[0]
154+
155+
output_jar = ctx.outputs.output_jar
156+
157+
input_jar = target_java_output.class_jar
158+
159+
_run_osgi_wrapper(ctx, input_jar, output_jar)
160+
161+
return [
162+
DefaultInfo(
163+
files = depset([output_jar]),
164+
# Workaround for https://github.com/bazelbuild/bazel/issues/15043
165+
# Bazel's native rule such as sh_test do not pick up 'files' in
166+
# DefaultInfo for a target in 'data'.
167+
data_runfiles = ctx.runfiles([output_jar]),
168+
),
169+
JavaInfo(
170+
output_jar = output_jar,
171+
172+
# compile_jar should be an ijar, but using an ijar results in
173+
# missing protobuf import version.
174+
compile_jar = output_jar,
175+
generated_class_jar = target_java_output.generated_class_jar,
176+
native_headers_jar = target_java_output.native_headers_jar,
177+
manifest_proto = target_java_output.manifest_proto,
178+
neverlink = ctx.attr.neverlink,
179+
deps = [dep[JavaInfo] for dep in ctx.attr.deps],
180+
runtime_deps = [dep[JavaInfo] for dep in ctx.attr.runtime_deps],
181+
exports = [exp[JavaInfo] for exp in ctx.attr.exports],
182+
exported_plugins = ctx.attr.exported_plugins,
183+
),
184+
]
185+
186+
_osgi_kt_jvm_jar = rule(
187+
implementation = _osgi_kt_jvm_jar_impl,
188+
outputs = {
189+
"output_jar": "lib%{name}.jar",
190+
},
191+
attrs = {
192+
"automatic_module_name": attr.string(),
193+
"bundle_copyright": attr.string(),
194+
"bundle_description": attr.string(),
195+
"bundle_doc_url": attr.string(),
196+
"bundle_license": attr.string(),
197+
"bundle_name": attr.string(),
198+
"bundle_version": attr.string(),
199+
"bundle_symbolic_name": attr.string(),
200+
"export_package": attr.string_list(),
201+
"import_package": attr.string_list(),
202+
"target": attr.label(),
203+
"deps": attr.label_list(),
204+
"runtime_deps": attr.label_list(),
205+
"exports": attr.label_list(),
206+
"neverlink": attr.bool(),
207+
"exported_plugins": attr.label_list(),
208+
"_osgi_wrapper_exe": attr.label(
209+
executable = True,
210+
cfg = "exec",
211+
allow_files = True,
212+
default = Label("//java/osgi:osgi_wrapper"),
213+
),
214+
},
215+
)

0 commit comments

Comments
 (0)