Skip to content

Commit 3ca60fb

Browse files
jadenPeteJaden Peterson
and
Jaden Peterson
authored
Enable scala_macro_library targets to have dependencies (#1681)
* Enabled ijar for scala_macro_library targets * Export a ScalaInfo provider * Include macros' transitive runtime dependencies on the compile classpath --------- Co-authored-by: Jaden Peterson <[email protected]>
1 parent bfb9b9e commit 3ca60fb

16 files changed

+182
-56
lines changed

scala/private/common.bzl

+27-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
load("@io_bazel_rules_scala//scala:jars_to_labels.bzl", "JarsToLabelsInfo")
22
load("@io_bazel_rules_scala//scala:plusone.bzl", "PlusOneDeps")
3+
load("@io_bazel_rules_scala//scala:providers.bzl", "ScalaInfo")
34
load("@bazel_skylib//lib:paths.bzl", "paths")
45

56
def write_manifest_file(actions, output_file, main_class):
@@ -22,6 +23,7 @@ def collect_jars(
2223
compile_jars = []
2324
runtime_jars = []
2425
deps_providers = []
26+
macro_classpath = []
2527

2628
for dep_target in dep_targets:
2729
# we require a JavaInfo for dependencies
@@ -50,11 +52,34 @@ def collect_jars(
5052
java_provider.compile_jars.to_list(),
5153
)
5254

55+
# Macros are different from ordinary targets in that they’re used at compile time instead of at runtime. That
56+
# means that both their compile-time classpath and runtime classpath are needed at compile time. We could have
57+
# `scala_macro_library` targets include their runtime dependencies in their compile-time dependencies, but then
58+
# we wouldn't have any guarantees classpath order.
59+
#
60+
# Consider the following scenario. Target A depends on targets B and C. Target C is a macro target, whereas
61+
# target B isn't. Targets C depends on target B. If target A doesn't include the runtime version of target C on
62+
# the compile classpath before the compile (`ijar`d) version of target B that target C depends on, then target A
63+
# won't use the correct version of target B at compile-time when evaluating the macros contained in target C.
64+
#
65+
# For that reason, we opt for a different approach: have `scala_macro_library` targets export `JavaInfo`
66+
# providers as normal, but put their transitive runtime dependencies first on the classpath. Note that we
67+
# shouldn't encounter any issues with external dependencies, so long as they aren't `ijar`d.
68+
if ScalaInfo in dep_target and dep_target[ScalaInfo].contains_macros:
69+
macro_classpath.append(java_provider.transitive_runtime_jars)
70+
71+
add_labels_of_jars_to(
72+
jars2labels,
73+
dep_target,
74+
[],
75+
java_provider.transitive_runtime_jars.to_list(),
76+
)
77+
5378
return struct(
54-
compile_jars = depset(transitive = compile_jars),
79+
compile_jars = depset(order = "preorder", transitive = macro_classpath + compile_jars),
5580
transitive_runtime_jars = depset(transitive = runtime_jars),
5681
jars2labels = JarsToLabelsInfo(jars_to_labels = jars2labels),
57-
transitive_compile_jars = depset(transitive = transitive_compile_jars),
82+
transitive_compile_jars = depset(order = "preorder", transitive = macro_classpath + transitive_compile_jars),
5883
deps_providers = deps_providers,
5984
)
6085

scala/private/phases/phase_compile.bzl

-11
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,6 @@ def phase_compile_library_for_plugin_bootstrapping(ctx, p):
4646
)
4747
return _phase_compile_default(ctx, p, args)
4848

49-
def phase_compile_macro_library(ctx, p):
50-
args = struct(
51-
buildijar = False,
52-
unused_dependency_checker_ignored_targets = [
53-
target.label
54-
for target in p.scalac_provider.default_macro_classpath + ctx.attr.exports +
55-
ctx.attr.unused_dependency_checker_ignored_targets
56-
],
57-
)
58-
return _phase_compile_default(ctx, p, args)
59-
6049
def phase_compile_junit_test(ctx, p):
6150
args = struct(
6251
buildijar = False,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
load("//scala:providers.bzl", "ScalaInfo")
2+
3+
def _phase_scalainfo_provider_implementation(contains_macros):
4+
return struct(
5+
external_providers = {
6+
"ScalaInfo": ScalaInfo(contains_macros = contains_macros),
7+
},
8+
)
9+
10+
def phase_scalainfo_provider_macro(ctx, p):
11+
return _phase_scalainfo_provider_implementation(contains_macros = True)
12+
13+
def phase_scalainfo_provider_non_macro(ctx, p):
14+
return _phase_scalainfo_provider_implementation(contains_macros = False)

scala/private/phases/phases.bzl

+35-28
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,6 @@ load(
77
_extras_phases = "extras_phases",
88
_run_phases = "run_phases",
99
)
10-
load(
11-
"@io_bazel_rules_scala//scala/private:phases/phase_write_executable.bzl",
12-
_phase_write_executable_common = "phase_write_executable_common",
13-
_phase_write_executable_junit_test = "phase_write_executable_junit_test",
14-
_phase_write_executable_repl = "phase_write_executable_repl",
15-
_phase_write_executable_scalatest = "phase_write_executable_scalatest",
16-
)
17-
load(
18-
"@io_bazel_rules_scala//scala/private:phases/phase_java_wrapper.bzl",
19-
_phase_java_wrapper_common = "phase_java_wrapper_common",
20-
_phase_java_wrapper_repl = "phase_java_wrapper_repl",
21-
)
2210
load(
2311
"@io_bazel_rules_scala//scala/private:phases/phase_collect_jars.bzl",
2412
_phase_collect_jars_common = "phase_collect_jars_common",
@@ -27,46 +15,62 @@ load(
2715
_phase_collect_jars_repl = "phase_collect_jars_repl",
2816
_phase_collect_jars_scalatest = "phase_collect_jars_scalatest",
2917
)
18+
load("@io_bazel_rules_scala//scala/private:phases/phase_collect_exports_jars.bzl", _phase_collect_exports_jars = "phase_collect_exports_jars")
19+
load("@io_bazel_rules_scala//scala/private:phases/phase_collect_srcjars.bzl", _phase_collect_srcjars = "phase_collect_srcjars")
3020
load(
3121
"@io_bazel_rules_scala//scala/private:phases/phase_compile.bzl",
3222
_phase_compile_binary = "phase_compile_binary",
3323
_phase_compile_common = "phase_compile_common",
3424
_phase_compile_junit_test = "phase_compile_junit_test",
3525
_phase_compile_library = "phase_compile_library",
3626
_phase_compile_library_for_plugin_bootstrapping = "phase_compile_library_for_plugin_bootstrapping",
37-
_phase_compile_macro_library = "phase_compile_macro_library",
3827
_phase_compile_repl = "phase_compile_repl",
3928
_phase_compile_scalatest = "phase_compile_scalatest",
4029
)
41-
load(
42-
"@io_bazel_rules_scala//scala/private:phases/phase_runfiles.bzl",
43-
_phase_runfiles_common = "phase_runfiles_common",
44-
_phase_runfiles_library = "phase_runfiles_library",
45-
_phase_runfiles_scalatest = "phase_runfiles_scalatest",
46-
)
4730
load(
4831
"@io_bazel_rules_scala//scala/private:phases/phase_coverage.bzl",
4932
_phase_coverage_common = "phase_coverage_common",
5033
_phase_coverage_library = "phase_coverage_library",
5134
)
35+
load("@io_bazel_rules_scala//scala/private:phases/phase_coverage_runfiles.bzl", _phase_coverage_runfiles = "phase_coverage_runfiles")
36+
load("@io_bazel_rules_scala//scala/private:phases/phase_declare_executable.bzl", _phase_declare_executable = "phase_declare_executable")
5237
load("@io_bazel_rules_scala//scala/private:phases/phase_default_info.bzl", _phase_default_info = "phase_default_info")
53-
load("@io_bazel_rules_scala//scala/private:phases/phase_scalac_provider.bzl", _phase_scalac_provider = "phase_scalac_provider")
54-
load("@io_bazel_rules_scala//scala/private:phases/phase_write_manifest.bzl", _phase_write_manifest = "phase_write_manifest")
55-
load("@io_bazel_rules_scala//scala/private:phases/phase_collect_srcjars.bzl", _phase_collect_srcjars = "phase_collect_srcjars")
56-
load("@io_bazel_rules_scala//scala/private:phases/phase_collect_exports_jars.bzl", _phase_collect_exports_jars = "phase_collect_exports_jars")
5738
load(
5839
"@io_bazel_rules_scala//scala/private:phases/phase_dependency.bzl",
5940
_phase_dependency_common = "phase_dependency_common",
6041
_phase_dependency_library_for_plugin_bootstrapping = "phase_dependency_library_for_plugin_bootstrapping",
6142
)
62-
load("@io_bazel_rules_scala//scala/private:phases/phase_declare_executable.bzl", _phase_declare_executable = "phase_declare_executable")
63-
load("@io_bazel_rules_scala//scala/private:phases/phase_merge_jars.bzl", _phase_merge_jars = "phase_merge_jars")
43+
load(
44+
"@io_bazel_rules_scala//scala/private:phases/phase_java_wrapper.bzl",
45+
_phase_java_wrapper_common = "phase_java_wrapper_common",
46+
_phase_java_wrapper_repl = "phase_java_wrapper_repl",
47+
)
6448
load("@io_bazel_rules_scala//scala/private:phases/phase_jvm_flags.bzl", _phase_jvm_flags = "phase_jvm_flags")
49+
load("@io_bazel_rules_scala//scala/private:phases/phase_merge_jars.bzl", _phase_merge_jars = "phase_merge_jars")
50+
load(
51+
"@io_bazel_rules_scala//scala/private:phases/phase_runfiles.bzl",
52+
_phase_runfiles_common = "phase_runfiles_common",
53+
_phase_runfiles_library = "phase_runfiles_library",
54+
_phase_runfiles_scalatest = "phase_runfiles_scalatest",
55+
)
56+
load("@io_bazel_rules_scala//scala/private:phases/phase_scalac_provider.bzl", _phase_scalac_provider = "phase_scalac_provider")
6557
load("@io_bazel_rules_scala//scala/private:phases/phase_scalacopts.bzl", _phase_scalacopts = "phase_scalacopts")
66-
load("@io_bazel_rules_scala//scala/private:phases/phase_coverage_runfiles.bzl", _phase_coverage_runfiles = "phase_coverage_runfiles")
6758
load("@io_bazel_rules_scala//scala/private:phases/phase_scalafmt.bzl", _phase_scalafmt = "phase_scalafmt")
68-
load("@io_bazel_rules_scala//scala/private:phases/phase_test_environment.bzl", _phase_test_environment = "phase_test_environment")
59+
load(
60+
"@io_bazel_rules_scala//scala/private:phases/phase_scalainfo_provider.bzl",
61+
_phase_scalainfo_provider_macro = "phase_scalainfo_provider_macro",
62+
_phase_scalainfo_provider_non_macro = "phase_scalainfo_provider_non_macro",
63+
)
6964
load("@io_bazel_rules_scala//scala/private:phases/phase_semanticdb.bzl", _phase_semanticdb = "phase_semanticdb")
65+
load("@io_bazel_rules_scala//scala/private:phases/phase_test_environment.bzl", _phase_test_environment = "phase_test_environment")
66+
load(
67+
"@io_bazel_rules_scala//scala/private:phases/phase_write_executable.bzl",
68+
_phase_write_executable_common = "phase_write_executable_common",
69+
_phase_write_executable_junit_test = "phase_write_executable_junit_test",
70+
_phase_write_executable_repl = "phase_write_executable_repl",
71+
_phase_write_executable_scalatest = "phase_write_executable_scalatest",
72+
)
73+
load("@io_bazel_rules_scala//scala/private:phases/phase_write_manifest.bzl", _phase_write_manifest = "phase_write_manifest")
7074

7175
# API
7276
run_phases = _run_phases
@@ -75,6 +79,10 @@ extras_phases = _extras_phases
7579
# scalac_provider
7680
phase_scalac_provider = _phase_scalac_provider
7781

82+
# scalainfo_provider
83+
phase_scalainfo_provider_macro = _phase_scalainfo_provider_macro
84+
phase_scalainfo_provider_non_macro = _phase_scalainfo_provider_non_macro
85+
7886
# collect_srcjars
7987
phase_collect_srcjars = _phase_collect_srcjars
8088

@@ -128,7 +136,6 @@ phase_collect_jars_common = _phase_collect_jars_common
128136
phase_compile_binary = _phase_compile_binary
129137
phase_compile_library = _phase_compile_library
130138
phase_compile_library_for_plugin_bootstrapping = _phase_compile_library_for_plugin_bootstrapping
131-
phase_compile_macro_library = _phase_compile_macro_library
132139
phase_compile_junit_test = _phase_compile_junit_test
133140
phase_compile_repl = _phase_compile_repl
134141
phase_compile_scalatest = _phase_compile_scalatest

scala/private/rules/scala_binary.bzl

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ load(
2424
"phase_runfiles_common",
2525
"phase_scalac_provider",
2626
"phase_scalacopts",
27+
"phase_scalainfo_provider_non_macro",
2728
"phase_semanticdb",
2829
"phase_write_executable_common",
2930
"phase_write_manifest",
@@ -36,6 +37,7 @@ def _scala_binary_impl(ctx):
3637
# customizable phases
3738
[
3839
("scalac_provider", phase_scalac_provider),
40+
("scalainfo_provider", phase_scalainfo_provider_non_macro),
3941
("write_manifest", phase_write_manifest),
4042
("dependency", phase_dependency_common),
4143
("collect_jars", phase_collect_jars_common),

scala/private/rules/scala_doc.bzl

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"""Scaladoc support"""
22

3+
load("@io_bazel_rules_scala//scala:providers.bzl", "ScalaInfo")
34
load("@io_bazel_rules_scala//scala/private:common.bzl", "collect_plugin_paths")
45

56
ScaladocAspectInfo = provider(fields = [
67
"src_files", #depset[File]
78
"compile_jars", #depset[File]
9+
"macro_classpath", #depset[File]
810
"plugins", #depset[Target]
911
])
1012

@@ -29,23 +31,28 @@ def _scaladoc_aspect_impl(target, ctx, transitive = True):
2931
if hasattr(ctx.rule.attr, "plugins"):
3032
plugins = depset(ctx.rule.attr.plugins)
3133

34+
macro_classpath = []
35+
36+
for dependency in ctx.rule.attr.deps:
37+
if ScalaInfo in dependency and dependency[ScalaInfo].contains_macros:
38+
macro_classpath.append(dependency[JavaInfo].transitive_runtime_jars)
39+
3240
# Sometimes we only want to generate scaladocs for a single target and not all of its
3341
# dependencies
3442
transitive_srcs = depset()
35-
transitive_compile_jars = depset()
3643
transitive_plugins = depset()
3744

3845
if transitive:
3946
for dep in ctx.rule.attr.deps:
4047
if ScaladocAspectInfo in dep:
4148
aspec_info = dep[ScaladocAspectInfo]
4249
transitive_srcs = aspec_info.src_files
43-
transitive_compile_jars = aspec_info.compile_jars
4450
transitive_plugins = aspec_info.plugins
4551

4652
return [ScaladocAspectInfo(
4753
src_files = depset(transitive = [src_files, transitive_srcs]),
48-
compile_jars = depset(transitive = [compile_jars, transitive_compile_jars]),
54+
compile_jars = depset(transitive = [compile_jars]),
55+
macro_classpath = depset(transitive = macro_classpath),
4956
plugins = depset(transitive = [plugins, transitive_plugins]),
5057
)]
5158

@@ -73,11 +80,15 @@ def _scala_doc_impl(ctx):
7380
src_files = depset(transitive = [dep[ScaladocAspectInfo].src_files for dep in ctx.attr.deps])
7481
compile_jars = depset(transitive = [dep[ScaladocAspectInfo].compile_jars for dep in ctx.attr.deps])
7582

83+
# See the documentation for `collect_jars` in `scala/private/common.bzl` to understand why this is prepended to the
84+
# classpath
85+
macro_classpath = depset(transitive = [dep[ScaladocAspectInfo].macro_classpath for dep in ctx.attr.deps])
86+
7687
# Get the 'real' paths to the plugin jars.
7788
plugins = collect_plugin_paths(depset(transitive = [dep[ScaladocAspectInfo].plugins for dep in ctx.attr.deps]).to_list())
7889

7990
# Construct the full classpath depset since we need to add compiler plugins too.
80-
classpath = depset(transitive = [plugins, compile_jars])
91+
classpath = depset(transitive = [macro_classpath, plugins, compile_jars])
8192

8293
# Construct scaladoc args, which also include scalac args.
8394
# See `scaladoc -help` for more information.

scala/private/rules/scala_junit_test.bzl

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ load(
2525
"phase_runfiles_common",
2626
"phase_scalac_provider",
2727
"phase_scalacopts",
28+
"phase_scalainfo_provider_non_macro",
2829
"phase_semanticdb",
2930
"phase_test_environment",
3031
"phase_write_executable_junit_test",
@@ -42,6 +43,7 @@ def _scala_junit_test_impl(ctx):
4243
# customizable phases
4344
[
4445
("scalac_provider", phase_scalac_provider),
46+
("scalainfo_provider", phase_scalainfo_provider_non_macro),
4547
("write_manifest", phase_write_manifest),
4648
("dependency", phase_dependency_common),
4749
("collect_jars", phase_collect_jars_junit_test),

scala/private/rules/scala_library.bzl

+6-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ load(
2525
"phase_collect_srcjars",
2626
"phase_compile_library",
2727
"phase_compile_library_for_plugin_bootstrapping",
28-
"phase_compile_macro_library",
2928
"phase_coverage_common",
3029
"phase_coverage_library",
3130
"phase_default_info",
@@ -35,6 +34,8 @@ load(
3534
"phase_runfiles_library",
3635
"phase_scalac_provider",
3736
"phase_scalacopts",
37+
"phase_scalainfo_provider_macro",
38+
"phase_scalainfo_provider_non_macro",
3839
"phase_semanticdb",
3940
"phase_write_manifest",
4041
"run_phases",
@@ -63,6 +64,7 @@ def _scala_library_impl(ctx):
6364
# customizable phases
6465
[
6566
("scalac_provider", phase_scalac_provider),
67+
("scalainfo_provider", phase_scalainfo_provider_non_macro),
6668
("collect_srcjars", phase_collect_srcjars),
6769
("write_manifest", phase_write_manifest),
6870
("dependency", phase_dependency_common),
@@ -151,6 +153,7 @@ def _scala_library_for_plugin_bootstrapping_impl(ctx):
151153
# customizable phases
152154
[
153155
("scalac_provider", phase_scalac_provider),
156+
("scalainfo_provider", phase_scalainfo_provider_non_macro),
154157
("collect_srcjars", phase_collect_srcjars),
155158
("write_manifest", phase_write_manifest),
156159
("dependency", phase_dependency_library_for_plugin_bootstrapping),
@@ -226,13 +229,14 @@ def _scala_macro_library_impl(ctx):
226229
# customizable phases
227230
[
228231
("scalac_provider", phase_scalac_provider),
232+
("scalainfo_provider", phase_scalainfo_provider_macro),
229233
("collect_srcjars", phase_collect_srcjars),
230234
("write_manifest", phase_write_manifest),
231235
("dependency", phase_dependency_common),
232236
("collect_jars", phase_collect_jars_macro_library),
233237
("scalacopts", phase_scalacopts),
234238
("semanticdb", phase_semanticdb),
235-
("compile", phase_compile_macro_library),
239+
("compile", phase_compile_library),
236240
("coverage", phase_coverage_common),
237241
("merge_jars", phase_merge_jars),
238242
("runfiles", phase_runfiles_library),

scala/private/rules/scala_repl.bzl

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ load(
2424
"phase_runfiles_common",
2525
"phase_scalac_provider",
2626
"phase_scalacopts",
27+
"phase_scalainfo_provider_non_macro",
2728
"phase_semanticdb",
2829
"phase_write_executable_repl",
2930
"phase_write_manifest",
@@ -36,6 +37,7 @@ def _scala_repl_impl(ctx):
3637
# customizable phases
3738
[
3839
("scalac_provider", phase_scalac_provider),
40+
("scalainfo_provider", phase_scalainfo_provider_non_macro),
3941
("write_manifest", phase_write_manifest),
4042
("dependency", phase_dependency_common),
4143
# need scala-compiler for MainGenericRunner below

scala/private/rules/scala_test.bzl

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ load(
2525
"phase_runfiles_scalatest",
2626
"phase_scalac_provider",
2727
"phase_scalacopts",
28+
"phase_scalainfo_provider_non_macro",
2829
"phase_semanticdb",
2930
"phase_test_environment",
3031
"phase_write_executable_scalatest",
@@ -38,6 +39,7 @@ def _scala_test_impl(ctx):
3839
# customizable phases
3940
[
4041
("scalac_provider", phase_scalac_provider),
42+
("scalainfo_provider", phase_scalainfo_provider_non_macro),
4143
("write_manifest", phase_write_manifest),
4244
("dependency", phase_dependency_common),
4345
("collect_jars", phase_collect_jars_scalatest),

0 commit comments

Comments
 (0)