blob: b444c169155bc86c34692a74c5430fbacfd2639e [file] [log] [blame]
# Copyright 2018 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
load("//kotlin/internal:kt.bzl", "kt")
load("//kotlin/internal:plugins.bzl", "plugins")
load("//kotlin/internal:utils.bzl", "utils")
def _declare_output_directory(ctx, aspect, dir_name):
return ctx.actions.declare_directory("_kotlinc/%s_%s/%s_%s" % (ctx.label.name, aspect, ctx.label.name, dir_name))
def _kotlin_do_compile_action(ctx, rule_kind, output_jar, compile_jars, module_name, friend_paths, srcs, src_jars):
"""Internal macro that sets up a Kotlin compile action.
This macro only supports a single Kotlin compile operation for a rule.
Args:
rule_kind: The rule kind,
output_jar: The jar file that this macro will use as the output of the action.
compile_jars: The compile time jars provided on the classpath for the compile operations -- callers are
responsible for preparing the classpath. The stdlib (and jdk7 + jdk8) should generally be added to the classpath
by the caller -- kotlin-reflect could be optional.
"""
classes_directory=_declare_output_directory(ctx, "jvm", "classes")
generated_classes_directory=_declare_output_directory(ctx, "jvm", "generated_classes")
sourcegen_directory=_declare_output_directory(ctx, "jvm", "sourcegenfiles")
temp_directory=_declare_output_directory(ctx, "jvm", "temp")
tc=ctx.toolchains[kt.defs.TOOLCHAIN_TYPE]
args = [
"--target_label", ctx.label,
"--rule_kind", rule_kind,
"--classdir", classes_directory.path,
"--sourcegendir", sourcegen_directory.path,
"--tempdir", temp_directory.path,
"--kotlin_generated_classdir", generated_classes_directory.path,
"--output", output_jar.path,
"--output_jdeps", ctx.outputs.jdeps.path,
"--classpath", "\n".join([f.path for f in compile_jars.to_list()]),
"--kotlin_friend_paths", "\n".join(friend_paths.to_list()),
"--kotlin_jvm_target", tc.jvm_target,
"--kotlin_api_version", tc.api_version,
"--kotlin_language_version", tc.language_version,
"--kotlin_module_name", module_name,
"--kotlin_passthrough_flags", "-Xcoroutines=%s" % tc.coroutines
]
if len(srcs) == 0 and len(src_jars) == 0:
fail("srcs did not contain kotlin/java files or any srcjars")
if len(srcs) > 0:
args += ["--sources", "\n".join(srcs)]
if len(src_jars) > 0:
args += ["--source_jars", "\n".join([sj.path for sj in src_jars])]
# Collect and prepare plugin descriptor for the worker.
plugin_info=plugins.merge_plugin_infos(ctx.attr.plugins + ctx.attr.deps)
if len(plugin_info.annotation_processors) > 0:
args += [ "--kt-plugins", plugin_info.to_json() ]
# Declare and write out argument file.
args_file = ctx.actions.declare_file(ctx.label.name + ".jar-2.params")
ctx.actions.write(args_file, "\n".join(args))
# When a stratetegy isn't provided for the worker and the workspace is fresh then certain deps are not available under
# external/@com_github_jetbrains_kotlin/... that is why the classpath is added explicetly.
compile_inputs = (
depset([args_file]) +
ctx.files.srcs +
compile_jars +
ctx.files._kotlin_compiler_classpath +
ctx.files._kotlin_home +
ctx.files._jdk)
ctx.action(
mnemonic = "KotlinCompile",
inputs = compile_inputs,
outputs = [
output_jar,
ctx.outputs.jdeps,
sourcegen_directory,
classes_directory,
temp_directory,
generated_classes_directory
],
executable = ctx.executable._kotlinw,
execution_requirements = {"supports-workers": "1"},
arguments = ["@" + args_file.path],
progress_message="Compiling %d Kotlin source files to %s" % (len(ctx.files.srcs), output_jar.short_path),
)
def _select_std_libs(ctx):
return ctx.files._kotlin_std
def _make_java_provider(ctx, input_deps=[], auto_deps=[], src_jars=[]):
"""Creates the java_provider for a Kotlin target.
This macro is distinct from the kotlin_make_providers as collecting the java_info is useful before the DefaultInfo is
created.
Args:
ctx: The ctx of the rule in scope when this macro is called. The macro will pick up the following entities from
the rule ctx:
* The default output jar.
* The `deps` for this provider.
* Optionally `exports` (see java rules).
* The `_kotlin_runtime` implicit dependency.
Returns:
A JavaInfo provider.
"""
deps=utils.collect_all_jars(input_deps)
exported_deps=utils.collect_all_jars(getattr(ctx.attr, "exports", []))
my_compile_jars = exported_deps.compile_jars + [ctx.outputs.jar]
my_runtime_jars = exported_deps.transitive_runtime_jars + [ctx.outputs.jar]
my_transitive_compile_jars = my_compile_jars + deps.transitive_compile_time_jars + exported_deps.transitive_compile_time_jars + auto_deps
my_transitive_runtime_jars = my_runtime_jars + deps.transitive_runtime_jars + exported_deps.transitive_runtime_jars + [ctx.file._kotlin_runtime] + auto_deps
# collect the runtime jars from the runtime_deps attribute.
for jar in ctx.attr.runtime_deps:
my_transitive_runtime_jars += jar[JavaInfo].transitive_runtime_jars
return java_common.create_provider(
use_ijar = False,
# A list or set of output source jars that contain the uncompiled source files including the source files
# generated by annotation processors if the case.
source_jars= src_jars + utils.actions.maybe_make_srcsjar(ctx),
# A list or a set of jars that should be used at compilation for a given target.
compile_time_jars = my_compile_jars,
# A list or a set of jars that should be used at runtime for a given target.
runtime_jars=my_runtime_jars,
transitive_compile_time_jars= my_transitive_compile_jars,
transitive_runtime_jars=my_transitive_runtime_jars
)
def _make_providers(ctx, java_info, module_name, transitive_files=depset(order="default")):
kotlin_info=kt.info.KtInfo(
srcs=ctx.files.srcs,
module_name = module_name,
# intelij aspect needs this.
outputs = struct(
jdeps = ctx.outputs.jdeps,
jars = [struct(
class_jar = ctx.outputs.jar,
ijar = None,
source_jars = java_info.source_jars
)]
),
)
default_info = DefaultInfo(
files=depset([ctx.outputs.jar]),
runfiles=ctx.runfiles(
transitive_files=transitive_files,
collect_default=True
),
)
return struct(
kt=kotlin_info,
providers=[java_info,default_info,kotlin_info],
)
def _compile_action(ctx, rule_kind, module_name, friend_paths=depset(), src_jars=[]):
"""Setup a kotlin compile action.
Args:
ctx: The rule context.
Returns:
A JavaInfo struct for the output jar that this macro will build.
"""
# The main output jars
output_jar = ctx.outputs.jar
# The output of the compile step may be combined (folded) with other entities -- e.g., other class files from annotation processing, embedded resources.
kt_compile_output_jar=output_jar
# the list of jars to merge into the final output, start with the resource jars if any were provided.
output_merge_list=ctx.files.resource_jars
# If this rule has any resources declared setup a zipper action to turn them into a jar and then add the declared zipper output to the merge list.
if len(ctx.files.resources) > 0:
output_merge_list = output_merge_list + [utils.actions.build_resourcejar(ctx)]
# If this compile operation requires merging other jars setup the compile operation to go to a intermediate file and add that file to the merge list.
if len(output_merge_list) > 0:
# Intermediate jar containing the Kotlin compile output.
kt_compile_output_jar=ctx.new_file(ctx.label.name + "-ktclass.jar")
# If we setup indirection than the first entry in the merge list is the result of the kotlin compile action.
output_merge_list=[ kt_compile_output_jar ] + output_merge_list
kotlin_auto_deps=_select_std_libs(ctx)
deps = ctx.attr.deps + getattr(ctx.attr, "friends", [])
srcs = []
src_jars = []
for f in ctx.files.srcs:
if f.path.endswith(".kt") or f.path.endswith(".java"):
srcs.append(f.path)
elif f.path.endswith(".srcjar"):
src_jars.append(f)
# setup the compile action.
_kotlin_do_compile_action(
ctx,
rule_kind = rule_kind,
output_jar = kt_compile_output_jar,
compile_jars = utils.collect_jars_for_compile(deps) + kotlin_auto_deps,
module_name = module_name,
friend_paths = friend_paths,
srcs = srcs,
src_jars = src_jars
)
# setup the merge action if needed.
if len(output_merge_list) > 0:
utils.actions.fold_jars(ctx, output_jar, output_merge_list)
# create the java provider but the kotlin and default provider cannot be created here.
return _make_java_provider(ctx, deps, kotlin_auto_deps, src_jars)
compile = struct(
compile_action = _compile_action,
make_providers = _make_providers,
)