rules_scala
rules_scala copied to clipboard
Rule for running onejar on plugins
If you attempt to use a scalac plugin such as scapegoat or silencer, you'll get the following warning from phase_classpaths:
WARNING! It is slightly inefficient to use a JVM target with dependencies directly as a scalac plugin. Please SingleJar the target before using it as a scalac plugin in order to avoid additional overhead.
[1] https://github.com/higherkindness/rules_scala/blob/master/rules/private/phases/phase_classpaths.bzl#L25
However, there is no available rule that makes it possible to "SingleJar" the target.
I wrote a quick rule that exposes the existing singlejar wrapper from rules_scala
, but that feels a bit wrong since needs to load the action_singlejar
from private/utils.bzl
. It seems like it would make sense to add such a rule to make it easier to package plugins?
load("@rules_scala_annex//rules/common:private/utils.bzl", _action_singlejar = "action_singlejar")
def _scala_plugin_impl(ctx):
plugin = ctx.attr.plugin
plugin_runtime_jars = plugin[JavaInfo].transitive_runtime_jars.to_list()
output_jar = ctx.outputs.plugin_singlejar
_action_singlejar(
ctx,
inputs = plugin_runtime_jars,
output = output_jar,
progress_message = "singlejar scalac plugin %s" % plugin.label.name,
)
return struct(
providers = [
JavaInfo(
output_jar = output_jar,
compile_jar = output_jar,
),
],
)
scala_plugin = rule(
implementation = _scala_plugin_impl,
attrs = {
"plugin": attr.label(
allow_single_file = True,
mandatory = True,
doc = "The Scalac plugin.",
providers = [JavaInfo],
),
"_singlejar": attr.label(
cfg = "host",
default = "@bazel_tools//tools/jdk:singlejar",
executable = True,
),
},
outputs = {
"plugin_singlejar": "%{name}_singlejar.jar",
},
)
Hey @bjchambers! Thanks for opening this issue. For plugins that are only referenced directly in one package (like global plugins you specify when configuring the compiler) this shouldn't be an issue (since we only run the singlejar action once either way).
However, if you're specifying a plugin in multiple projects (for instance, directly in the plugins
attribute of multiple scala_library/scala_binary targets) then the current approach would singlejar the plugin multiple times. A scala_plugin
rule could help in those cases.
Are you seeing the warning multiple times?
I'm only seeing the warning once, but I theorized that is because I have enabled de-duplicating messages. When I used the above to explicitly run onejar
in the top-level BUILD
where I was defining the global plugins, the total number of actions executed on a clean build was reduced by 57, which made me suspect that the onejar was actually being produced multiple times.
If this really only happens once, it would be good if there was a way to suppress the warning the first time. Could the code that produces this warning (and runs onejar) detect that is being used as part of setting the global plugins and not log?
scalac expects each plugin to be fully isolated, so we need to smash everything together with singlejar
Really? This contradicts https://github.com/sbt/sbt/issues/2255 which claims that the entire plugin classpath is shared.