diff options
author | hsyed <h.a.syed@gmail.com> | 2018-08-10 00:19:37 +0100 |
---|---|---|
committer | Hassan Syed <h.a.syed@gmail.com> | 2018-08-10 12:44:58 +0100 |
commit | 43dad811064a9f79b2e644c2924bec7fb2fcfb2a (patch) | |
tree | 6751c0973b5bf77a73d9ab4c2ddcdadb07a399b3 | |
parent | 4ec34499110e17cb79b64cc2dc638cbdebc74235 (diff) | |
download | bazelbuild-rules-kotlin-43dad811064a9f79b2e644c2924bec7fb2fcfb2a.tar.gz |
reorganize skylark layout to support another aspect
29 files changed, 1048 insertions, 1075 deletions
@@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. workspace(name="io_bazel_rules_kotlin") -load("//kotlin/internal:bootstrap.bzl",github_archive="github_archive") +load("//kotlin/internal/repositories:repositories.bzl","github_archive") github_archive( name = "com_google_protobuf", diff --git a/kotlin/BUILD b/kotlin/BUILD index e7ab37c..af730cc 100644 --- a/kotlin/BUILD +++ b/kotlin/BUILD @@ -13,37 +13,11 @@ # limitations under the License. package(default_visibility = ["//visibility:public"]) -load("//kotlin:toolchains.bzl", "define_kt_toolchain") -load("//kotlin/internal:bootstrap.bzl", "kt_toolchain_ide_info") - -config_setting( - name = "builder_debug_timings", - values = { "define": "kt_timings=1" } -) - -config_setting( - name = "builder_debug_trace", - values = { "define": "kt_trace=1" } -) - -define_kt_toolchain( - name = "default_toolchain", - debug= - select({ - "//kotlin:builder_debug_trace": ["trace"], - "//conditions:default": [] - }) + - select({ - "//kotlin:builder_debug_timings": ["timings"], - "//conditions:default": [] - }) -) +load("//kotlin/internal:toolchains.bzl", "kt_toolchain_ide_info") toolchain_type( name = "kt_toolchain_type", visibility = ["//visibility:public"] ) -kt_toolchain_ide_info(name="kt_toolchain_ide_info") - -exports_files(["toolchains.bzl", "kotlin.bzl"], visibility=["//docs:__subpackages__"]) +kt_toolchain_ide_info(name="kt_toolchain_ide_info")
\ No newline at end of file diff --git a/kotlin/builder/integrationtests/KotlinBuilderActionTests.java b/kotlin/builder/integrationtests/KotlinBuilderActionTests.java index 257af8b..a8516bf 100644 --- a/kotlin/builder/integrationtests/KotlinBuilderActionTests.java +++ b/kotlin/builder/integrationtests/KotlinBuilderActionTests.java @@ -6,7 +6,7 @@ public class KotlinBuilderActionTests extends KotlinBuilderTestCase { @Test public void testCompileSimple() { addSource("AClass.kt", "package something;" + "class AClass{}"); - component().jvmCompiler().compile(builderCommand()); + component().jvmTaskExecutor().compileKotlin(builderCommand(), context()); assertFileExists(DirectoryType.CLASSES, "something/AClass.class"); assertFileDoesNotExist(outputs().getJar()); } diff --git a/kotlin/builder/integrationtests/KotlinBuilderTestCase.java b/kotlin/builder/integrationtests/KotlinBuilderTestCase.java index 3bfa7db..c5759b5 100644 --- a/kotlin/builder/integrationtests/KotlinBuilderTestCase.java +++ b/kotlin/builder/integrationtests/KotlinBuilderTestCase.java @@ -3,6 +3,7 @@ package io.bazel.kotlin.builder; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import io.bazel.kotlin.builder.toolchain.KotlinToolchain; +import io.bazel.kotlin.builder.utils.CompilationTaskContext; import io.bazel.kotlin.model.JvmCompilationTask; import io.bazel.kotlin.model.KotlinToolchainInfo; import io.bazel.kotlin.model.Platform; @@ -28,9 +29,7 @@ abstract class KotlinBuilderTestCase { private final JvmCompilationTask.Builder builder = JvmCompilationTask.newBuilder(); private final KotlinBuilderComponent component = - DaggerKotlinBuilderComponent.builder() - .toolchain(KotlinToolchain.createToolchain()) - .build(); + DaggerKotlinBuilderComponent.builder().toolchain(KotlinToolchain.createToolchain()).build(); private String label = null; private Path inputSourceDir = null; @@ -56,6 +55,10 @@ abstract class KotlinBuilderTestCase { return Paths.get(directories().getClasses()); } + protected CompilationTaskContext context() { + return new CompilationTaskContext(builder.getInfo(), System.err); + } + protected JvmCompilationTask builderCommand() { return builder.build(); } diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderComponent.java b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderComponent.java index db95f4d..deeedad 100644 --- a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderComponent.java +++ b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderComponent.java @@ -20,14 +20,12 @@ import dagger.Component; import dagger.Provides; import io.bazel.kotlin.builder.tasks.BazelWorker; import io.bazel.kotlin.builder.tasks.KotlinBuilder; -import io.bazel.kotlin.builder.tasks.jvm.KotlinJvmCompiler; import io.bazel.kotlin.builder.tasks.jvm.KotlinJvmTaskExecutor; import io.bazel.kotlin.builder.toolchain.KotlinToolchain; import io.bazel.kotlin.builder.utils.KotlinCompilerPluginArgsEncoder; import javax.inject.Singleton; import java.io.PrintStream; -import java.util.function.Supplier; @Singleton @dagger.Component(modules = {KotlinBuilderComponent.Module.class}) @@ -36,8 +34,6 @@ public interface KotlinBuilderComponent { KotlinJvmTaskExecutor jvmTaskExecutor(); - KotlinJvmCompiler jvmCompiler(); - BazelWorker worker(); @Component.Builder diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt index c834790..2c7ebfc 100644 --- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt +++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt @@ -71,7 +71,7 @@ class KotlinBuilder @Inject internal constructor( private fun buildContext(args: List<String>): Pair<ArgMap, CompilationTaskContext> { check(args.isNotEmpty()) { "expected at least a single arg got: ${args.joinToString(" ")}" } - val (flagFileName, primaryOutputPath, idx) = + val (flagFileName, primaryOutputPath, _) = checkNotNull(FLAGFILE_RE.matchEntire(args[0])) { "invalid flagfile ${args[0]}" }.destructured val argMap = Files.readAllLines(Paths.get(flagFileName), StandardCharsets.UTF_8).let(ArgMaps::from) val info = buildTaskInfo(argMap).also { diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt deleted file mode 100644 index b4b5bb5..0000000 --- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - */ -package io.bazel.kotlin.builder.tasks.jvm - -import io.bazel.kotlin.builder.toolchain.CompilationStatusException -import io.bazel.kotlin.builder.toolchain.KotlinToolchain -import io.bazel.kotlin.builder.utils.CompilationTaskContext -import io.bazel.kotlin.builder.utils.KotlinCompilerPluginArgsEncoder -import io.bazel.kotlin.builder.utils.addAll -import io.bazel.kotlin.builder.utils.joinedClasspath -import io.bazel.kotlin.model.JvmCompilationTask -import java.io.ByteArrayInputStream -import java.io.ByteArrayOutputStream -import java.io.File -import java.io.PrintStream -import javax.inject.Inject -import javax.inject.Singleton - - -// The Kotlin compiler is not suited for javac compilation as of 1.2.21. The errors are not conveyed directly and would need to be preprocessed, also javac -// invocations Configured via Kotlin use eager analysis in some corner cases this can result in classpath exceptions from the Java Compiler.. -// -// 1 is a standard compilation error -// 2 is an internal error -// 3 is the script execution error -@Singleton -internal class KotlinJvmCompiler @Inject constructor( - private val compiler: KotlinToolchain.KotlincInvoker, - private val pluginArgsEncoder: KotlinCompilerPluginArgsEncoder -) { - fun runAnnotationProcessor(context: CompilationTaskContext, command: JvmCompilationTask): List<String> { - check(command.info.plugins.annotationProcessorsList.isNotEmpty()) { - "method called without annotation processors" - } - return getCommonArgs(command).also { - it.addAll(pluginArgsEncoder.encode(context, command)) - it.addAll(command.inputs.kotlinSourcesList) - it.addAll(command.inputs.javaSourcesList) - }.let(::invokeCompilePhase) - } - - /** - * Return a list with the common arguments. - */ - private fun getCommonArgs(command: JvmCompilationTask): MutableList<String> { - val args = mutableListOf<String>() - - // use -- for flags not meant for the kotlin compiler - args.addAll( - "-cp", command.inputs.joinedClasspath, - "-api-version", command.info.toolchainInfo.common.apiVersion, - "-language-version", command.info.toolchainInfo.common.languageVersion, - "-jvm-target", command.info.toolchainInfo.jvm.jvmTarget, - // https://github.com/bazelbuild/rules_kotlin/issues/69: remove once jetbrains adds a flag for it. - "--friend-paths", command.info.friendPathsList.joinToString(File.pathSeparator) - ) - - args - .addAll("-module-name", command.info.moduleName) - .addAll("-d", command.directories.classes) - - command.info.passthroughFlags?.takeIf { it.isNotBlank() }?.also { args.addAll(it.split(" ")) } - return args - } - - fun compile(command: JvmCompilationTask): List<String> = - with(getCommonArgs(command)) { - addAll(command.inputs.javaSourcesList) - addAll(command.inputs.kotlinSourcesList) - invokeCompilePhase(this) - } - - private fun invokeCompilePhase(args: List<String>): List<String> { - val outputStream = ByteArrayOutputStream() - val ps = PrintStream(outputStream) - val result = compiler.compile(args.toTypedArray(), ps) - val output = ByteArrayInputStream(outputStream.toByteArray()).bufferedReader().readLines() - if (result != 0) { - throw CompilationStatusException("compile phase failed", result, output) - } else { - return output - } - } -}
\ No newline at end of file diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt index bac2bcd..4a56c44 100644 --- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt +++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt @@ -16,6 +16,7 @@ package io.bazel.kotlin.builder.tasks.jvm import io.bazel.kotlin.builder.toolchain.CompilationStatusException +import io.bazel.kotlin.builder.toolchain.KotlinToolchain import io.bazel.kotlin.builder.utils.* import io.bazel.kotlin.builder.utils.jars.JarCreator import io.bazel.kotlin.builder.utils.jars.SourceJarCreator @@ -29,7 +30,8 @@ import javax.inject.Singleton @Singleton class KotlinJvmTaskExecutor @Inject internal constructor( - private val kotlinCompiler: KotlinJvmCompiler, + private val compiler: KotlinToolchain.KotlincInvoker, + private val pluginArgsEncoder: KotlinCompilerPluginArgsEncoder, private val javaCompiler: JavaCompiler, private val jDepsGenerator: JDepsGenerator ) { @@ -37,7 +39,7 @@ class KotlinJvmTaskExecutor @Inject internal constructor( // TODO fix error handling try { val preprocessedTask = task.preprocessingSteps(context) - context.execute("compile classes") { preprocessedTask.compileClasses(context) } + context.execute("compile classes") { preprocessedTask.compileAll(context) } context.execute("create jar") { preprocessedTask.createOutputJar() } context.execute("produce src jar") { preprocessedTask.produceSourceJar() } context.execute("generate jdeps") { preprocessedTask.generateJDeps() } @@ -83,6 +85,42 @@ class KotlinJvmTaskExecutor @Inject internal constructor( } } + private fun JvmCompilationTask.runAnnotationProcessor(context: CompilationTaskContext): List<String> { + check(info.plugins.annotationProcessorsList.isNotEmpty()) { + "method called without annotation processors" + } + return getCommonArgs().let { args -> + args.addAll(pluginArgsEncoder.encode(context, this)) + args.addAll(inputs.kotlinSourcesList) + args.addAll(inputs.javaSourcesList) + context.executeCompilerTask(args, false, compiler::compile) + } + } + + /** + * Return a list with the common arguments. + */ + private fun JvmCompilationTask.getCommonArgs(): MutableList<String> { + val args = mutableListOf<String>() + + // use -- for flags not meant for the kotlin compiler + args.addAll( + "-cp", inputs.joinedClasspath, + "-api-version", info.toolchainInfo.common.apiVersion, + "-language-version", info.toolchainInfo.common.languageVersion, + "-jvm-target", info.toolchainInfo.jvm.jvmTarget, + // https://github.com/bazelbuild/rules_kotlin/issues/69: remove once jetbrains adds a flag for it. + "--friend-paths", info.friendPathsList.joinToString(File.pathSeparator) + ) + + args + .addAll("-module-name", info.moduleName) + .addAll("-d", directories.classes) + + info.passthroughFlags?.takeIf { it.isNotBlank() }?.also { args.addAll(it.split(" ")) } + return args + } + private fun JvmCompilationTask.runAnnotationProcessors( context: CompilationTaskContext ): JvmCompilationTask = @@ -90,7 +128,7 @@ class KotlinJvmTaskExecutor @Inject internal constructor( if (info.plugins.annotationProcessorsList.isEmpty()) { this } else { - val kaptOutput = kotlinCompiler.runAnnotationProcessor(context, this) + val kaptOutput = runAnnotationProcessor(context) context.whenTracing { printLines("kapt output", kaptOutput) } expandWithGeneratedSources() } @@ -114,7 +152,7 @@ class KotlinJvmTaskExecutor @Inject internal constructor( it.execute() } - private fun JvmCompilationTask.compileClasses(context: CompilationTaskContext) { + private fun JvmCompilationTask.compileAll(context: CompilationTaskContext) { ensureDirectories( directories.classes ) @@ -122,7 +160,7 @@ class KotlinJvmTaskExecutor @Inject internal constructor( var result: List<String>? = null context.execute("kotlinc") { result = try { - kotlinCompiler.compile(this) + compileKotlin(context) } catch (ex: CompilationStatusException) { kotlinError = ex ex.lines @@ -139,6 +177,16 @@ class KotlinJvmTaskExecutor @Inject internal constructor( } /** + * Compiles Kotlin sources to classes. Does not compile Java sources. + */ + fun JvmCompilationTask.compileKotlin(context: CompilationTaskContext): List<String> = + getCommonArgs().let { args -> + args.addAll(inputs.javaSourcesList) + args.addAll(inputs.kotlinSourcesList) + context.executeCompilerTask(args, false, compiler::compile) + } + + /** * If any srcjars were provided expand the jars sources and create a new [JvmCompilationTask] with the * Java and Kotlin sources merged in. */ diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt b/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt index 1f39682..3b74053 100644 --- a/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt +++ b/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt @@ -108,6 +108,10 @@ class KotlinToolchain private constructor( getCodeMethod = exitCodeClass.getMethod("getCode") } + // Kotlin error codes: + // 1 is a standard compilation error + // 2 is an internal error + // 3 is the script execution error fun compile(args: Array<String>, out: PrintStream): Int { val exitCodeInstance = execMethod.invoke(compiler, out, args) return getCodeMethod.invoke(exitCodeInstance, *NO_ARGS) as Int @@ -118,6 +122,11 @@ class KotlinToolchain private constructor( class KotlincInvoker @Inject constructor( toolchain: KotlinToolchain ) : KotlinCliToolInvoker(toolchain, "io.bazel.kotlin.compiler.BazelK2JVMCompiler") + + @Singleton + class K2JSCompilerInvoker @Inject constructor( + toolchain: KotlinToolchain + ) : KotlinCliToolInvoker(toolchain, "org.jetbrains.kotlin.cli.js.K2JSCompiler") } diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/utils/CompilationTaskContext.kt b/kotlin/builder/src/io/bazel/kotlin/builder/utils/CompilationTaskContext.kt index fc85d0a..8712d88 100644 --- a/kotlin/builder/src/io/bazel/kotlin/builder/utils/CompilationTaskContext.kt +++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/CompilationTaskContext.kt @@ -18,7 +18,10 @@ package io.bazel.kotlin.builder.utils import com.google.protobuf.MessageOrBuilder import com.google.protobuf.TextFormat +import io.bazel.kotlin.builder.toolchain.CompilationStatusException import io.bazel.kotlin.model.CompilationTaskInfo +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream import java.io.File import java.io.PrintStream import java.nio.file.Paths @@ -35,7 +38,9 @@ class CompilationTaskContext(val info: CompilationTaskInfo, private val out: Pri isTracing = debugging.contains("trace") } - fun reportUnhandledException(throwable: Throwable) { throwable.printStackTrace(out) } + fun reportUnhandledException(throwable: Throwable) { + throwable.printStackTrace(out) + } /** * Print a list of debugging lines. @@ -57,7 +62,9 @@ class CompilationTaskContext(val info: CompilationTaskInfo, private val out: Pri } inline fun <T> whenTracing(block: CompilationTaskContext.() -> T): T? { - return if(isTracing) { block() } else null + return if (isTracing) { + block() + } else null } /** @@ -82,6 +89,31 @@ class CompilationTaskContext(val info: CompilationTaskInfo, private val out: Pri } /** + * Execute a compilation task. + * + * @throws CompilationStatusException if the compiler returns a status of anything but zero. + * @param args the compiler command line switches + * @param deliverOutput if this is true the output will be printed to out directly. + * @param compile the compilation method. + */ + inline fun executeCompilerTask( + args: List<String>, + deliverOutput: Boolean, + compile: (Array<String>, PrintStream) -> Int + ): List<String> { + val outputStream = ByteArrayOutputStream() + val ps = PrintStream(outputStream) + val result = compile(args.toTypedArray(), ps) + val output = ByteArrayInputStream(outputStream.toByteArray()).bufferedReader().readLines() + if (result != 0) { + throw CompilationStatusException("compile phase failed", result, output) + } else if(deliverOutput) { + printCompilerOutput(output) + } + return output + } + + /** * Runs a task and records the timings. */ fun <T> execute(name: String, task: () -> T): T { @@ -104,7 +136,7 @@ class CompilationTaskContext(val info: CompilationTaskInfo, private val out: Pri * @param succesfull true if the task finished succesfully. */ fun finalize(succesfull: Boolean) { - if(succesfull) { + if (succesfull) { timings?.also { printLines("Task timings", it, prefix = " * ") } } } diff --git a/kotlin/internal/BUILD b/kotlin/internal/BUILD index 37e64eb..6561c52 100644 --- a/kotlin/internal/BUILD +++ b/kotlin/internal/BUILD @@ -10,4 +10,28 @@ # 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.
\ No newline at end of file +# limitations under the License. +load("//kotlin/internal:toolchains.bzl", "define_kt_toolchain") + +config_setting( + name = "builder_debug_timings", + values = { "define": "kt_timings=1" } +) + +config_setting( + name = "builder_debug_trace", + values = { "define": "kt_trace=1" } +) + +define_kt_toolchain( + name = "default_toolchain", + debug= + select({ + ":builder_debug_trace": ["trace"], + "//conditions:default": [] + }) + + select({ + ":builder_debug_timings": ["timings"], + "//conditions:default": [] + }) +)
\ No newline at end of file diff --git a/kotlin/internal/bootstrap.bzl b/kotlin/internal/bootstrap.bzl deleted file mode 100644 index 05cbbaf..0000000 --- a/kotlin/internal/bootstrap.bzl +++ /dev/null @@ -1,57 +0,0 @@ -# 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. -"""This file contains rules used to bootstrap the compiler repository.""" - -load("//kotlin/internal:kt.bzl", "kt") -load("//kotlin/internal:rules.bzl", _kt_jvm_import_impl="kt_jvm_import_impl") -load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive="http_archive") - -def _kt_toolchain_ide_info_impl(ctx): - tc=ctx.toolchains[kt.defs.TOOLCHAIN_TYPE] - info = struct( - label = tc.label, - common = struct( - language_version = tc.language_version, - api_version = tc.api_version, - coroutines = tc.coroutines - ), - jvm = struct( - jvm_target = tc.jvm_target, - ) - ) - ctx.actions.write(ctx.outputs.ide_info, info.to_json()) - return [DefaultInfo(files=depset([ctx.outputs.ide_info]))] - -kt_toolchain_ide_info = rule( - outputs = {"ide_info": "kt_toolchain_ide_info.json"}, - toolchains = [kt.defs.TOOLCHAIN_TYPE], - implementation = _kt_toolchain_ide_info_impl, -) - -def github_archive(name, repo, commit, build_file_content = None): - if build_file_content: - _http_archive( - name = name, - strip_prefix = "%s-%s" % (repo.split("/")[1], commit), - url = "https://github.com/%s/archive/%s.zip" % (repo, commit), - type = "zip", - build_file_content = build_file_content, - ) - else: - _http_archive( - name = name, - strip_prefix = "%s-%s" % (repo.split("/")[1], commit), - url = "https://github.com/%s/archive/%s.zip" % (repo, commit), - type = "zip", - ) diff --git a/kotlin/internal/common/BUILD b/kotlin/internal/common/BUILD new file mode 100644 index 0000000..9c0f139 --- /dev/null +++ b/kotlin/internal/common/BUILD @@ -0,0 +1,13 @@ +# 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. diff --git a/kotlin/internal/common/common.bzl b/kotlin/internal/common/common.bzl new file mode 100644 index 0000000..ceee057 --- /dev/null +++ b/kotlin/internal/common/common.bzl @@ -0,0 +1,49 @@ +load("//kotlin/internal:defs.bzl", _TOOLCHAIN_TYPE="TOOLCHAIN_TYPE") + +def _restore_label(l): + lbl = l.workspace_root + if lbl.startswith("external/"): + lbl = lbl.replace("external/", "@") + return lbl + "//" + l.package + ":" + l.name + +def _derive_module_name(ctx): + module_name=getattr(ctx.attr, "module_name", "") + if module_name == "": + module_name = (ctx.label.package.lstrip("/").replace("/","_") + "-" + ctx.label.name.replace("/", "_")) + return module_name + +def _init_builder_args(ctx, rule_kind, module_name): + toolchain=ctx.toolchains[_TOOLCHAIN_TYPE] + + args = ctx.actions.args() + args.set_param_file_format("multiline") + args.use_param_file("--flagfile=%s", use_always=True) + + args.add("--target_label", ctx.label) + args.add("--rule_kind", rule_kind) + args.add("--kotlin_module_name", module_name) + + args.add("--kotlin_jvm_target", toolchain.jvm_target) + args.add("--kotlin_api_version", toolchain.api_version) + args.add("--kotlin_language_version", toolchain.language_version) + args.add("--kotlin_passthrough_flags", "-Xcoroutines=%s" % toolchain.coroutines) + + debug = depset(toolchain.debug) + for tag in ctx.attr.tags: + if tag == "trace": + debug = debug + [tag] + if tag == "timings": + debug = debug + [tag] + args.add("--kotlin_debug", debug) + + return args + +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)) + +common = struct( + init_args = _init_builder_args, + declare_output_directory = _declare_output_directory, + restore_label = _restore_label, + derive_module_name = _derive_module_name, +)
\ No newline at end of file diff --git a/kotlin/internal/compile.bzl b/kotlin/internal/compile.bzl deleted file mode 100644 index 47e45a4..0000000 --- a/kotlin/internal/compile.bzl +++ /dev/null @@ -1,216 +0,0 @@ -# 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 _common_init_args(ctx, rule_kind, module_name): - toolchain=ctx.toolchains[kt.defs.TOOLCHAIN_TYPE] - - args = ctx.actions.args() - args.set_param_file_format("multiline") - args.use_param_file("--flagfile=%s", use_always=True) - - args.add("--target_label", ctx.label) - args.add("--rule_kind", rule_kind) - args.add("--kotlin_module_name", module_name) - - args.add("--kotlin_jvm_target", toolchain.jvm_target) - args.add("--kotlin_api_version", toolchain.api_version) - args.add("--kotlin_language_version", toolchain.language_version) - args.add("--kotlin_passthrough_flags", "-Xcoroutines=%s" % toolchain.coroutines) - - debug = depset(toolchain.debug) - for tag in ctx.attr.tags: - if tag == "trace": - debug = debug + [tag] - if tag == "timings": - debug = debug + [tag] - args.add("--kotlin_debug", debug) - - return args - -def _kotlin_do_compile_action(ctx, rule_kind, output_jar, compile_jars, module_name, friend_paths, srcs): - """This macro performs a compile operation in a single action. - - Args: - rule_kind: The rule kind, - output_jar: The jar file that this macro will use as the output of the action. - module_name: The Kotlin module name, this must be provided and is used by the compiler for symbol mangling in - advanced use cases. - 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. - friend_paths: A list of jars paths that this compilation unit should have package private access to. - srcs: a struct with the various input sources partitioned. - """ - 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") - - toolchain=ctx.toolchains[kt.defs.TOOLCHAIN_TYPE] - args = _common_init_args(ctx, rule_kind, module_name) - - args.add("--classdir", classes_directory) - args.add("--sourcegendir", sourcegen_directory) - args.add("--tempdir", temp_directory) - args.add("--kotlin_generated_classdir", generated_classes_directory) - - args.add("--output", output_jar) - args.add("--kotlin_output_jdeps", ctx.outputs.jdeps) - args.add("--kotlin_output_srcjar", ctx.outputs.srcjar) - - args.add("--kotlin_friend_paths", "\n".join(friend_paths.to_list())) - - args.add("--classpath", compile_jars) - args.add_all("--sources", srcs.all_srcs, omit_if_empty=True) - args.add_all("--source_jars", srcs.src_jars, omit_if_empty=True) - - # 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.add("--kotlin_plugins", plugin_info.to_json()) - - progress_message = "Compiling Kotlin %s { kt: %d, java: %d, srcjars: %d }" % ( - ctx.label, - len(srcs.kt), - len(srcs.java), - len(srcs.src_jars) - ) - - inputs, _, input_manifests = ctx.resolve_command(tools = [toolchain.kotlinbuilder]) - ctx.actions.run( - mnemonic = "KotlinCompile", - inputs = depset(inputs) + ctx.files.srcs + compile_jars, - outputs = [ - output_jar, - ctx.outputs.jdeps, - ctx.outputs.srcjar, - sourcegen_directory, - classes_directory, - temp_directory, - generated_classes_directory - ], - executable = toolchain.kotlinbuilder.files_to_run.executable, - execution_requirements = {"supports-workers": "1"}, - arguments = [args], - progress_message = progress_message, - input_manifests = input_manifests - ) - -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 = [ctx.outputs.srcjar] - )] - ), - ) - - 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 - - srcs = utils.partition_srcs(ctx.files.srcs) - - if (len(srcs.kt) + len(srcs.java) == 0) and len(srcs.src_jars) == 0: - fail("no sources provided") - - toolchain=ctx.toolchains[kt.defs.TOOLCHAIN_TYPE] - - deps = [ - d[JavaInfo] - for d in ( - getattr(ctx.attr, "friends", []) + - ctx.attr.deps - ) - ] + [toolchain.jvm_stdlibs] - - # setup the compile action. - _kotlin_do_compile_action( - ctx, - rule_kind = rule_kind, - output_jar = kt_compile_output_jar, - compile_jars = java_common.merge(deps).compile_jars, - module_name = module_name, - friend_paths = friend_paths, - srcs = srcs - ) - - # setup the merge action if needed. - if len(output_merge_list) > 0: - utils.actions.fold_jars(ctx, rule_kind, output_jar, output_merge_list) - - # create the java provider but the kotlin and default provider cannot be created here. - return JavaInfo( - output_jar = ctx.outputs.jar, - compile_jar = ctx.outputs.jar, - source_jar = ctx.outputs.srcjar, -# jdeps = ctx.outputs.jdeps, - deps = deps, - runtime_deps = [d[JavaInfo] for d in ctx.attr.runtime_deps], - exports = [d[JavaInfo] for d in getattr(ctx.attr, "exports", [])], - neverlink = getattr(ctx.attr, "neverlink", False) - ) - -compile = struct( - compile_action = _compile_action, - make_providers = _make_providers, -) diff --git a/kotlin/internal/defs.bzl b/kotlin/internal/defs.bzl new file mode 100644 index 0000000..e1d23c1 --- /dev/null +++ b/kotlin/internal/defs.bzl @@ -0,0 +1,27 @@ +# 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.# + +# The Kotlin Toolchain type. +TOOLCHAIN_TYPE = "@io_bazel_rules_kotlin//kotlin:kt_toolchain_type" + +# The name of the Kotlin compiler workspace. +KT_COMPILER_REPO = "com_github_jetbrains_kotlin" + +KtInfo = provider( + fields = { + "module_name": "the module name", + "srcs": "the source files. [intelij-aspect]", + "outputs": "output jars produced by this rule. [intelij-aspect]", + }, +) diff --git a/kotlin/internal/jvm/BUILD b/kotlin/internal/jvm/BUILD new file mode 100644 index 0000000..37e64eb --- /dev/null +++ b/kotlin/internal/jvm/BUILD @@ -0,0 +1,13 @@ +# 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.
\ No newline at end of file diff --git a/kotlin/internal/jvm/compile.bzl b/kotlin/internal/jvm/compile.bzl new file mode 100644 index 0000000..465c730 --- /dev/null +++ b/kotlin/internal/jvm/compile.bzl @@ -0,0 +1,288 @@ +# 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:defs.bzl", "KtInfo", "TOOLCHAIN_TYPE") +load("//kotlin/internal/jvm:plugins.bzl", "plugins") +load("//kotlin/internal/common:common.bzl", "common") + +# MISC UTILS ########################################################################################################### +def _partition_srcs(srcs): + kt_srcs = [] + java_srcs = [] + src_jars = [] + + for f in srcs: + if f.path.endswith(".kt"): + kt_srcs.append(f) + elif f.path.endswith(".java"): + java_srcs.append(f) + elif f.path.endswith(".srcjar"): + src_jars.append(f) + + kt = depset(kt_srcs) + java = depset(java_srcs) + + return struct ( + kt = kt, + java = java, + all_srcs = kt + java, + src_jars = depset(src_jars) + ) + +# JAR ACTIONS ########################################################################################################## +def _fold_jars_action(ctx, rule_kind, output_jar, input_jars): + args=[ + "--normalize", + "--compression", + "--deploy_manifest_lines", + "Target-Label: %s" % str(ctx.label), + "Injecting-Rule-Kind: %s" % rule_kind, + "--output", output_jar.path + ] + for i in input_jars: + args += ["--sources", i.path] + ctx.action( + mnemonic = "KotlinFoldOutput", + inputs = input_jars, + outputs = [output_jar], + executable = ctx.executable._singlejar, + arguments = args, + progress_message="Merging Kotlin output jar " + output_jar.short_path + ) + +_CONVENTIONAL_RESOURCE_PATHS = [ + "src/main/resources", + "src/test/resources", +] + +def _adjust_resources_path_by_strip_prefix(path, resource_strip_prefix): + if not path.startswith(resource_strip_prefix): + fail("Resource file %s is not under the specified prefix to strip" % path) + + clean_path = path[len(resource_strip_prefix):] + return resource_strip_prefix, clean_path + +def _adjust_resources_path_by_default_prefixes(path): + for cp in _CONVENTIONAL_RESOURCE_PATHS: + dir_1, dir_2, rel_path = path.partition(cp) + if rel_path: + return dir_1 + dir_2, rel_path + return "", path + +def _adjust_resources_path(path, resource_strip_prefix): + if resource_strip_prefix: + return _adjust_resources_path_by_strip_prefix(path,resource_strip_prefix) + else: + return _adjust_resources_path_by_default_prefixes(path) + +def _add_resources_cmd(ctx): + res_cmd = [] + for f in ctx.files.resources: + c_dir, res_path = _adjust_resources_path(f.short_path, ctx.attr.resource_strip_prefix) + target_path = res_path + if target_path[0] == "/": + target_path = target_path[1:] + line = "{target_path}={c_dir}{res_path}\n".format( + res_path=res_path, + target_path=target_path, + c_dir=c_dir) + res_cmd.extend([line]) + return "".join(res_cmd) + +def _build_resourcejar_action(ctx): + resources = _add_resources_cmd(ctx) + resources_jar_output = ctx.actions.declare_file(ctx.label.name + "-resources.jar") + zipper_arg_path = ctx.actions.declare_file("%s_resources_zipper_args" % ctx.label.name) + ctx.file_action(zipper_arg_path, resources) + cmd = """ +rm -f {resources_jar_output} +{zipper} c {resources_jar_output} @{path} +""".format( + path=zipper_arg_path.path, + resources_jar_output=resources_jar_output.path, + zipper=ctx.executable._zipper.path, + ) + ctx.action( + mnemonic="KotlinZipResourceJar", + inputs=ctx.files.resources + [ctx.executable._zipper,zipper_arg_path], + outputs=[resources_jar_output], + command=cmd, + progress_message="Creating intermediate resource jar %s" % ctx.label, + arguments=[] + ) + return resources_jar_output + +def kt_jvm_compile_action(ctx, rule_kind, output_jar, srcs): + """This macro performs a compile operation in a single action. + + Args: + rule_kind: The rule kind, + output_jar: The jar file that this macro will use as the output of the action. + module_name: The Kotlin module name, this must be provided and is used by the compiler for symbol mangling in + advanced use cases. + 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. + friend_paths: A list of jars paths that this compilation unit should have package private access to. + srcs: a struct with the various input sources partitioned. + """ + toolchain=ctx.toolchains[TOOLCHAIN_TYPE] + + friends=getattr(ctx.attr, "friends", []) + deps = [d[JavaInfo] for d in friends + ctx.attr.deps] + [toolchain.jvm_stdlibs] + compile_jars = java_common.merge(deps).compile_jars + + if len(friends) == 0: + module_name=common.derive_module_name(ctx) + friend_paths=depset() + elif len(friends) == 1: + if friends[0][KtInfo] == None: + fail("only kotlin dependencies can be friends") + elif ctx.attr.module_name: + fail("if friends has been set then module_name cannot be provided") + else: + friend_paths=depset([j.path for j in friends[0][JavaInfo].compile_jars]) + module_name = friends[0][KtInfo].module_name + else: + fail("only one friend is possible") + + classes_directory=common.declare_output_directory(ctx, "jvm", "classes") + generated_classes_directory=common.declare_output_directory(ctx, "jvm", "generated_classes") + sourcegen_directory=common.declare_output_directory(ctx, "jvm", "sourcegenfiles") + temp_directory=common.declare_output_directory(ctx, "jvm", "temp") + + args = common.init_args(ctx, rule_kind, module_name) + + args.add("--classdir", classes_directory) + args.add("--sourcegendir", sourcegen_directory) + args.add("--tempdir", temp_directory) + args.add("--kotlin_generated_classdir", generated_classes_directory) + + args.add("--output", output_jar) + args.add("--kotlin_output_jdeps", ctx.outputs.jdeps) + args.add("--kotlin_output_srcjar", ctx.outputs.srcjar) + + args.add("--kotlin_friend_paths", "\n".join(friend_paths.to_list())) + + args.add("--classpath", compile_jars) + args.add_all("--sources", srcs.all_srcs, omit_if_empty=True) + args.add_all("--source_jars", srcs.src_jars, omit_if_empty=True) + + # 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.add("--kotlin_plugins", plugin_info.to_json()) + + progress_message = "Compiling Kotlin %s { kt: %d, java: %d, srcjars: %d }" % ( + ctx.label, + len(srcs.kt), + len(srcs.java), + len(srcs.src_jars) + ) + + inputs, _, input_manifests = ctx.resolve_command(tools = [toolchain.kotlinbuilder]) + ctx.actions.run( + mnemonic = "KotlinCompile", + inputs = depset(inputs) + ctx.files.srcs + compile_jars, + outputs = [ + output_jar, + ctx.outputs.jdeps, + ctx.outputs.srcjar, + sourcegen_directory, + classes_directory, + temp_directory, + generated_classes_directory + ], + executable = toolchain.kotlinbuilder.files_to_run.executable, + execution_requirements = {"supports-workers": "1"}, + arguments = [args], + progress_message = progress_message, + input_manifests = input_manifests + ) + + # create the java provider and the kotlin provider. Whilst a struct is being returned, and this is a valid way of + # creating a provider, it is intended that the client transforms this into an form. + return struct( + java=JavaInfo( + output_jar = ctx.outputs.jar, + compile_jar = ctx.outputs.jar, + source_jar = ctx.outputs.srcjar, + # jdeps = ctx.outputs.jdeps, + deps = deps, + runtime_deps = [d[JavaInfo] for d in ctx.attr.runtime_deps], + exports = [d[JavaInfo] for d in getattr(ctx.attr, "exports", [])], + neverlink = getattr(ctx.attr, "neverlink", False) + ), + kt=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 = [ctx.outputs.srcjar] + )] + ), + ) + ) + +def kt_jvm_produce_jar_actions(ctx, rule_kind, src_jars=[]): + """Setup a kotlin compile action. This method takes care of all of the aspects of producing a jar. + + Specifically this action will conditionally set up actions to fold resources and resourcejars and merge them onto a + jar compiled by the builder. It indirects the output_jar -- i.e., if no resources or resource jars are present it + won't do anything. + + 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 + [_build_resourcejar_action(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 + + srcs = _partition_srcs(ctx.files.srcs) + + if (len(srcs.kt) + len(srcs.java) == 0) and len(srcs.src_jars) == 0: + fail("no sources provided") + + # setup the merge action if needed. + if len(output_merge_list) > 0: + _fold_jars_action(ctx, rule_kind, output_jar, output_merge_list) + + # setup the compile action. + return kt_jvm_compile_action( + ctx, + rule_kind = rule_kind, + output_jar = kt_compile_output_jar, + srcs = srcs + ) + diff --git a/kotlin/internal/rules.bzl b/kotlin/internal/jvm/impl.bzl index 79ee8b1..bbc2133 100644 --- a/kotlin/internal/rules.bzl +++ b/kotlin/internal/jvm/impl.bzl @@ -11,10 +11,50 @@ # 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/jvm:compile.bzl", _kt_jvm_produce_jar_actions="kt_jvm_produce_jar_actions") +load("//kotlin/internal:defs.bzl", _KtJvmInfo="KtJvmInfo") + +def _make_providers(ctx, providers, transitive_files=depset(order="default")): + return struct( + kt=providers.kt, + providers=[ + providers.java, + providers.kt, + DefaultInfo( + files=depset([ctx.outputs.jar]), + runfiles=ctx.runfiles( + transitive_files=transitive_files, + collect_default=True + ), + ) + ], + ) -load("//kotlin/internal:compile.bzl", "compile") -load("//kotlin/internal:kt.bzl", "kt") -load("//kotlin/internal:utils.bzl", "utils") +def _write_launcher_action(ctx, rjars, main_class, jvm_flags, args="", wrapper_preamble=""): + """Macro that writes out a launcher script shell script. + Args: + rjars: All of the runtime jars required to launch this java target. + main_class: the main class to launch. + jvm_flags: The flags that should be passed to the jvm. + args: Args that should be passed to the Binary. + """ + classpath = ":".join(["${RUNPATH}%s" % (j.short_path) for j in rjars.to_list()]) + jvm_flags = " ".join([ctx.expand_location(f, ctx.attr.data) for f in jvm_flags]) + template = ctx.attr._java_stub_template.files.to_list()[0] + + ctx.actions.expand_template( + template = template, + output = ctx.outputs.executable, + substitutions = { + "%classpath%": classpath, + "%java_start_class%": main_class, + "%javabin%": "JAVABIN=${RUNPATH}" + ctx.executable._java.short_path, + "%jvm_flags%": jvm_flags, + "%set_jacoco_metadata%": "", + "%workspace_prefix%": ctx.workspace_name + "/", + }, + is_executable = True, + ) def kt_jvm_import_impl(ctx): jars = depset() @@ -71,70 +111,49 @@ def kt_jvm_import_impl(ctx): else: artifacts += [struct(class_jar=jar, ijar = None)] - kotlin_info=kt.info.KtInfo(outputs=struct(jars=artifacts)) + kotlin_info=_KtJvmInfo(outputs=struct(jars=artifacts)) default_info = DefaultInfo(files=depset(jars)) return struct(kt = kotlin_info, providers= [default_info, java_info, kotlin_info]) def kt_jvm_library_impl(ctx): - module_name=utils.derive_module_name(ctx) - return compile.make_providers( + return _make_providers( ctx, - compile.compile_action(ctx, "kt_jvm_library", module_name), - module_name, - ) + _kt_jvm_produce_jar_actions(ctx, "kt_jvm_library") + ) def kt_jvm_binary_impl(ctx): - module_name=utils.derive_module_name(ctx) - java_info = compile.compile_action(ctx, "kt_jvm_binary", module_name) - utils.actions.write_launcher( + providers = _kt_jvm_produce_jar_actions(ctx, "kt_jvm_binary") + _write_launcher_action( ctx, - java_info.transitive_runtime_jars, + providers.java.transitive_runtime_jars, ctx.attr.main_class, ctx.attr.jvm_flags ) - return compile.make_providers( + return _make_providers( ctx, - java_info, - module_name, + providers, depset( order = "default", - transitive=[java_info.transitive_runtime_jars], + transitive=[providers.java.transitive_runtime_jars], direct=[ctx.executable._java] ), ) def kt_jvm_junit_test_impl(ctx): - module_name=utils.derive_module_name(ctx) - friend_paths=depset() - - friends=getattr(ctx.attr, "friends", []) - if len(friends) > 1: - fail("only one friend is possible") - elif len(friends) == 1: - if friends[0][kt.info.KtInfo] == None: - fail("only kotlin dependencies can be friends") - else: - friend_paths += [j.path for j in friends[0][JavaInfo].compile_jars] - module_name = friends[0][kt.info.KtInfo].module_name - - java_info = compile.compile_action(ctx, "kt_jvm_test", module_name,friend_paths) - - transitive_runtime_jars = java_info.transitive_runtime_jars + ctx.files._bazel_test_runner - launcherJvmFlags = ["-ea", "-Dbazel.test_suite=%s"% ctx.attr.test_class] - - utils.actions.write_launcher( + providers = _kt_jvm_produce_jar_actions(ctx, "kt_jvm_test") + runtime_jars=providers.java.transitive_runtime_jars + ctx.files._bazel_test_runner + _write_launcher_action( ctx, - transitive_runtime_jars, + runtime_jars, main_class = ctx.attr.main_class, - jvm_flags = launcherJvmFlags + ctx.attr.jvm_flags, + jvm_flags = ["-ea", "-Dbazel.test_suite=%s"% ctx.attr.test_class] + ctx.attr.jvm_flags, ) - return compile.make_providers( + return _make_providers( ctx, - java_info, - module_name, + providers, depset( order = "default", - transitive=[transitive_runtime_jars], + transitive=[runtime_jars], direct=[ctx.executable._java] ), )
\ No newline at end of file diff --git a/kotlin/internal/jvm/jvm.bzl b/kotlin/internal/jvm/jvm.bzl new file mode 100644 index 0000000..ad12784 --- /dev/null +++ b/kotlin/internal/jvm/jvm.bzl @@ -0,0 +1,355 @@ +# 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. +"""Kotlin Rules + +### Setup + +Add the following snippet to your `WORKSPACE` file: + +```bzl +git_repository( + name = "io_bazel_rules_kotlin", + remote = "https://github.com/bazelbuild/rules_kotlin.git", + commit = "<COMMIT_HASH>", +) +load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kotlin_repositories", "kt_register_toolchains") +kotlin_repositories(kotlin_release_version = "1.2.21") +kt_register_toolchains() +``` + +To enable persistent worker support, add the following to the appropriate `bazelrc` file: + +``` +build --strategy=KotlinCompile=worker +test --strategy=KotlinCompile=worker +``` + + +### Standard Libraries + +The Kotlin libraries that are bundled in a kotlin release should be used with the rules, the mandatory standard libraries are added implicetly. After enabling +the repository the following Kotlin Libraries are also made available from the workspace `com_github_jetbrains_kotlin`: + +* `kotlin-test`, +* `kotlin-reflect`. + +So if you needed to add reflect as a dep use the following label `@com_github_jetbrains_kotlin//:kotlin-reflect`. + +### Mixed Mode compilation + +The JVM rules can compile both Java and Kotlin sources. The Java compiler wrapper is not optimized or persistent and does not have the features found in the +native java rules. This mode is usefull for migrating a package to Kotlin over time. + +### Annotation Processing + +Annotation processing works just as it does in Java, plugins are declared via a [`java_plugin`](https://docs.bazel.build/versions/master/be/java.html#java_plugin) +and may also be inherited from a `java_library` via the `exported_plugins` attribute. Annotation work in mixed-mode compilation and the Kotlin compiler take +care of processing both aspects. + +An example which can be found under `//examples/dagger`: + +```bzl +java_plugin( + name = "dagger_plugin", + deps = [ + "@dagger_compiler//jar", + "@guava//jar", + "@dagger_producers//jar", + "@dagger//jar", + "@javax_inject//jar" + ], + processor_class = "dagger.internal.codegen.ComponentProcessor" +) + +java_library( + name = "dagger_lib", + exports = [ + "@javax_inject//jar", + "@dagger//jar", + ], + exported_plugins = ["dagger_plugin"] +) + +kt_jvm_binary( + name = "dagger", + srcs = glob(["src/**"]), + main_class = "coffee.CoffeeApp", + deps = [":dagger_lib"], +) +``` +""" +# This file is the main import -- it shouldn't grow out of hand the reason it contains so much allready is due to the limitations of skydoc. + +######################################################################################################################## +# Common Definitions +######################################################################################################################## +load("//kotlin/internal:defs.bzl","KtInfo","TOOLCHAIN_TYPE") +# struct can't be used till skydoc is removed +load( + "//kotlin/internal/jvm:plugins.bzl", + _kt_jvm_plugin_aspect="kt_jvm_plugin_aspect", +) +# struct can't be used till skydoc is removed +load("//kotlin/internal/jvm:impl.bzl", + "kt_jvm_binary_impl", + "kt_jvm_import_impl", + "kt_jvm_junit_test_impl", + "kt_jvm_library_impl", +) + + +######################################################################################################################## +# Rule Attributes +######################################################################################################################## +_implicit_deps = { + "_kotlin_toolchain": attr.label_list( + default = [ + Label("@io_bazel_rules_kotlin//kotlin:kt_toolchain_ide_info"), + ], + cfg="host", + allow_files = False, + ), + "_singlejar": attr.label( + executable = True, + cfg = "host", + default = Label("@bazel_tools//tools/jdk:singlejar"), + allow_files = True, + ), + "_zipper": attr.label( + executable = True, + cfg = "host", + default = Label("@bazel_tools//tools/zip:zipper"), + allow_files = True, + ), + "_java": attr.label( + executable = True, + cfg = "host", + default = Label("@bazel_tools//tools/jdk:java"), + allow_files = True, + ), + "_java_stub_template": attr.label( + cfg = "host", + default = Label("@kt_java_stub_template//file"), + ), +} + +_common_attr = dict(_implicit_deps.items() + { + "srcs": attr.label_list( + default = [], + allow_files = [".srcjar", ".kt", ".java"], + ), + "deps": attr.label_list( + aspects = [_kt_jvm_plugin_aspect], + providers=[ + [JavaInfo], + ], + allow_files = False), + "runtime_deps": attr.label_list(default = [], allow_files=False), + "resources": attr.label_list( + default = [], + allow_files = True, + ), + "resource_strip_prefix": attr.string(default = ""), + "resource_jars": attr.label_list(default = []), + "data": attr.label_list( + allow_files = True, + cfg = "data", + ), + "plugins": attr.label_list( + default = [], + aspects = [_kt_jvm_plugin_aspect], + ), + "module_name": attr.string( + mandatory = False + ), +}.items()) + +_runnable_common_attr = dict(_common_attr.items() + { + "jvm_flags": attr.string_list( + default = [], + ), +}.items()) + +######################################################################################################################## +# Outputs: All the outputs produced by the various rules are modelled here. +######################################################################################################################## +_common_outputs = dict( + jar = "%{name}.jar", + jdeps = "%{name}.jdeps", + # The params file, declared here so that validate it can be validated for testing. +# jar_2_params = "%{name}.jar-2.params", + srcjar = "%{name}-sources.jar", +) + +_binary_outputs = dict(_common_outputs.items() + { +}.items()) + + + +######################################################################################################################## +# Simple Rules: +######################################################################################################################## +kt_jvm_library = rule( + attrs = dict(_common_attr.items() + { + "exports": attr.label_list(default = [], providers=[JavaInfo]), + "neverlink": attr.bool(default=False), + }.items()), + outputs = _common_outputs, + toolchains = [TOOLCHAIN_TYPE], + implementation = kt_jvm_library_impl, + provides = [JavaInfo, KtInfo] +) + +"""This rule compiles and links Kotlin and Java sources into a .jar file. +Args: + srcs: The list of source files that are processed to create the target, this can contain both Java and Kotlin files. Java analysis occurs first so Kotlin + classes may depend on Java classes in the same compilation unit. + exports: Exported libraries. + + Deps listed here will be made available to other rules, as if the parents explicitly depended on these deps. + This is not true for regular (non-exported) deps. + resources: A list of data files to include in a Java jar. + resource_strip_prefix: The path prefix to strip from Java resources, files residing under common prefix such as `src/main/resources` or `src/test/resources` + will have stripping applied by convention. + resource_jars: Set of archives containing Java resources. If specified, the contents of these jars are merged into the output jar. + runtime_deps: Libraries to make available to the final binary or test at runtime only. Like ordinary deps, these will appear on the runtime classpath, but + unlike them, not on the compile-time classpath. + data: The list of files needed by this rule at runtime. See general comments about `data` at [Attributes common to all build rules](https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes). + deps: A list of dependencies of this rule.See general comments about `deps` at [Attributes common to all build rules](https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes). + module_name: The name of the module, if not provided the module name is derived from the label. --e.g., `//some/package/path:label_name` is translated to + `some_package_path-label_name`. + neverlink: If true only use this library for compilation and not at runtime. +""" + +kt_jvm_binary = rule( + attrs = dict(_runnable_common_attr.items() + { + "main_class": attr.string(mandatory = True) + }.items()), + executable = True, + outputs = _binary_outputs, + toolchains = [TOOLCHAIN_TYPE], + implementation = kt_jvm_binary_impl, +) + +"""Builds a Java archive ("jar file"), plus a wrapper shell script with the same name as the rule. The wrapper shell script uses a classpath that includes, +among other things, a jar file for each library on which the binary depends. + +**Note:** This rule does not have all of the features found in [`java_binary`](https://docs.bazel.build/versions/master/be/java.html#java_binary). It is +appropriate for building workspace utilities. `java_binary` should be preferred for release artefacts. + +Args: + main_class: Name of class with main() method to use as entry point. + jvm_flags: A list of flags to embed in the wrapper script generated for running this binary. Note: does not yet support make variable substitution. +""" + +kt_jvm_test = rule( + attrs = dict(_runnable_common_attr.items() + { + "_bazel_test_runner": attr.label( + default = Label("@bazel_tools//tools/jdk:TestRunner_deploy.jar"), + allow_files = True, + ), + "friends": attr.label_list( + default = [], + providers = [JavaInfo, KtInfo] + ), + "test_class": attr.string(), + "main_class": attr.string(default="com.google.testing.junit.runner.BazelTestRunner"), + }.items()), + executable = True, + outputs = _binary_outputs, + test = True, + toolchains = [TOOLCHAIN_TYPE], + implementation = kt_jvm_junit_test_impl, +) + +"""Setup a simple kotlin_test. + +**Notes:** +* The kotlin test library is not added implicitly, it is available with the label `@com_github_jetbrains_kotlin//:kotlin-test`. + +Args: + test_class: The Java class to be loaded by the test runner. + friends: A single Kotlin dep which allows the test code access to internal members. Currently uses the output jar of + the module -- i.e., exported deps won't be included. +""" + +kt_jvm_import = rule( + attrs = { + "jars": attr.label_list( + allow_files = True, + mandatory = True, + cfg = "target", + ), + "srcjar": attr.label( + allow_single_file = True, + cfg = "target", + ), + "runtime_deps": attr.label_list( + default = [], + mandatory = False, + providers = [JavaInfo] + ) + }, + implementation = kt_jvm_import_impl, + provides = [JavaInfo, KtInfo] +) + +# The pairing of src and class is used by intellij to attatch sources, this is picked up via the kt provider attribute. +# +# once current format and semantics are finalized add runtime_deps, exports, data, neverlink, testonly. +# * runtime_deps should accept JavaInfo's (this includes KotlinInfo) and maven_jar filegroups. +# * exports should only accept JavaInfo's (this include KotlinInfo) but not filegroup. The jars attribute takes care of importing the jars without generating +# ijars. +"""(experimental) Import Kotlin jars. + +**Status:** This rule is not a counterpart to `java_import`. The current purpose for this rule is to import a kotlin jar without creating ijars. It will +eventually [be replaced](https://github.com/bazelbuild/rules_kotlin/issues/4) with `java_import`. If there is a need for expanding this rule we can instead +create a utility macro that delegates to this. + +## examples + +```bzl +# Old style usage -- reference file groups, do not used this. +kt_jvm_import( + name = "kodein", + jars = [ + "@com_github_salomonbrys_kodein_kodein//jar:file", + "@com_github_salomonbrys_kodein_kodein_core//jar:file" + ] +) + +# This style will pull in the transitive runtime dependencies of the targets as well. +kt_jvm_import( + name = "kodein", + jars = [ + "@com_github_salomonbrys_kodein_kodein//jar", + "@com_github_salomonbrys_kodein_kodein_core//jar" + ] +) + +# Import a single kotlin jar. +kt_jvm_import( + name = "kotlin-runtime", + jars = ["lib/kotlin-runtime.jar"], + srcjar = "lib/kotlin-runtime-sources.jar" +) +``` + +Args: + jars: The jars listed here are equavalent to an export attribute. The label should be either to a single class jar, or multiple filegroup labels. When the + labels is a file_provider it should follow the conventions used in repositories generated by the maven_jar rule --i.e., the rule expects a file_provider + with a single class jar and a single source jar. a source jar is recognized by the suffix `-sources.jar`. + srcjar: The sources for the class jar. This should be set when importing a single class jar. + runtime_deps: Additional runtime deps. +""" diff --git a/kotlin/internal/plugins.bzl b/kotlin/internal/jvm/plugins.bzl index 1a29eae..ab61a6f 100644 --- a/kotlin/internal/plugins.bzl +++ b/kotlin/internal/jvm/plugins.bzl @@ -11,7 +11,14 @@ # 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") +KtJvmPluginInfo = provider( + doc = "This provider contains the plugin info for the JVM aspect", + fields = { + "annotation_processors": "a serializeable list of structs containing annotation processor definitions", + }, +) + +_EMPTY_PLUGIN_INFO = [KtJvmPluginInfo(annotation_processors = [])] def _mk_processor_entry(l,p): merged_info=java_common.merge([j[JavaInfo] for j in p.deps]) @@ -27,12 +34,14 @@ def _mk_processor_entry(l,p): def _merge_plugin_infos(attrs): tally={} annotation_processors=[] - for info in [a[kt.info.KtPluginInfo] for a in attrs]: + for info in [a[KtJvmPluginInfo] for a in attrs]: for p in info.annotation_processors: if p.label not in tally: tally[p.label] = True annotation_processors.append(p) - return kt.info.KtPluginInfo(annotation_processors=annotation_processors) + return KtJvmPluginInfo( + annotation_processors=annotation_processors + ) def _restore_label(l): lbl = l.workspace_root @@ -40,11 +49,9 @@ def _restore_label(l): lbl = lbl.replace("external/", "@") return lbl + "//" + l.package + ":" + l.name -_EMPTY_PLUGIN_INFO = [kt.info.KtPluginInfo(annotation_processors = [])] - def _kt_jvm_plugin_aspect_impl(target, ctx): if ctx.rule.kind == "java_plugin": - return [kt.info.KtPluginInfo( + return [KtJvmPluginInfo( annotation_processors = [_mk_processor_entry(_restore_label(ctx.label),ctx.rule.attr)] )] else: @@ -54,10 +61,13 @@ def _kt_jvm_plugin_aspect_impl(target, ctx): return _EMPTY_PLUGIN_INFO kt_jvm_plugin_aspect = aspect( + doc = """This aspect processes collects Java Plugins info so that annotation processors may be configured for a +rule.""", attr_aspects = [ "plugins", "exported_plugins", ], + provides = [KtJvmPluginInfo], implementation = _kt_jvm_plugin_aspect_impl, ) diff --git a/kotlin/internal/kt.bzl b/kotlin/internal/kt.bzl deleted file mode 100644 index c660e70..0000000 --- a/kotlin/internal/kt.bzl +++ /dev/null @@ -1,46 +0,0 @@ -# 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. -######################################################################################################################## -# Providers -######################################################################################################################## -_defs = struct( - DEFAULT_TOOLCHAIN = "@io_bazel_rules_kotlin//kotlin:default_toolchain", - # The name of the Kotlin compiler workspace. - KT_COMPILER_REPO = "com_github_jetbrains_kotlin", - # The name of the rules repo. Centralised so it's easy to change. - REPO_ROOT = "io_bazel_rules_kotlin", - TOOLCHAIN_TYPE = "@io_bazel_rules_kotlin//kotlin:kt_toolchain_type", -) - -_KtInfo = provider( - fields = { - "srcs": "the source files. [intelij-aspect]", - "module_name": "the module name", - "outputs": "output jars produced by this rule. [intelij-aspect]", - }, -) - -_KtPluginInfo = provider( - fields = { - "annotation_processors": "a serializeable list of structs containing an annotation processor definitions", - }, -) - -kt = struct( - defs = _defs, - info = struct( - KtInfo = _KtInfo, - KtPluginInfo = _KtPluginInfo, - ), -) diff --git a/kotlin/internal/repositories/BUILD b/kotlin/internal/repositories/BUILD new file mode 100644 index 0000000..37e64eb --- /dev/null +++ b/kotlin/internal/repositories/BUILD @@ -0,0 +1,13 @@ +# 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.
\ No newline at end of file diff --git a/kotlin/BUILD.com_github_jetbrains_kotlin b/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin index a2311f8..a2311f8 100644 --- a/kotlin/BUILD.com_github_jetbrains_kotlin +++ b/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin diff --git a/kotlin/kotlin_releases.bzl b/kotlin/internal/repositories/compiler_releases.bzl index c7753e9..c7753e9 100644 --- a/kotlin/kotlin_releases.bzl +++ b/kotlin/internal/repositories/compiler_releases.bzl diff --git a/kotlin/kotlin_compiler_repositories.bzl b/kotlin/internal/repositories/repositories.bzl index 6161285..3faa13c 100644 --- a/kotlin/kotlin_compiler_repositories.bzl +++ b/kotlin/internal/repositories/repositories.bzl @@ -14,30 +14,45 @@ """This file contains the Kotlin compiler repository definitions. It should not be loaded directly by client workspaces. """ load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_file="http_file", _http_archive="http_archive") -load("//kotlin/internal:kt.bzl", _kt = "kt") -load("//kotlin:kotlin_releases.bzl", - _KOTLIN_COMPILER_RELEASES="KOTLIN_COMPILER_RELEASES", - _KOTLIN_CURRENT_RELEASE="KOTLIN_CURRENT_RELEASE" -) +load("//kotlin/internal:defs.bzl", "KT_COMPILER_REPO") +load("//kotlin/internal/repositories:compiler_releases.bzl", "KOTLIN_COMPILER_RELEASES", "KOTLIN_CURRENT_RELEASE") +load("//third_party/jvm:workspace.bzl", _maven_dependencies="maven_dependencies") _BAZEL_JAVA_LAUNCHER_VERSION = "0.8.1" -def kotlin_compiler_repositories(kotlin_release_version): +def github_archive(name, repo, commit, build_file_content = None): + if build_file_content: + _http_archive( + name = name, + strip_prefix = "%s-%s" % (repo.split("/")[1], commit), + url = "https://github.com/%s/archive/%s.zip" % (repo, commit), + type = "zip", + build_file_content = build_file_content, + ) + else: + _http_archive( + name = name, + strip_prefix = "%s-%s" % (repo.split("/")[1], commit), + url = "https://github.com/%s/archive/%s.zip" % (repo, commit), + type = "zip", + ) + +def _compiler_repositories(kotlin_release_version): """ Prime the compiler repository. This function should not be called directly instead `kotlin_repositories` from `//kotlin:kotlin.bzl` should be called to ensure common deps are loaded. """ - release=_KOTLIN_COMPILER_RELEASES[kotlin_release_version] + release=KOTLIN_COMPILER_RELEASES[kotlin_release_version] if not release: - fail('"%s" not a valid kotlin release, current release is "%s"' % (kotlin_release_version, _KOTLIN_CURRENT_RELEASE)) + fail('"%s" not a valid kotlin release, current release is "%s"' % (kotlin_release_version, KOTLIN_CURRENT_RELEASE)) _http_archive( - name = _kt.defs.KT_COMPILER_REPO, + name = KT_COMPILER_REPO, url = release["url"], sha256 = release["sha256"], - build_file= "@io_bazel_rules_kotlin//kotlin:BUILD.com_github_jetbrains_kotlin", + build_file= "@io_bazel_rules_kotlin//kotlin/internal/repositories:BUILD.com_github_jetbrains_kotlin", strip_prefix = "kotlinc", ) @@ -49,3 +64,15 @@ def kotlin_compiler_repositories(kotlin_release_version): "java_stub_template.txt")], sha256 = "86660ee7d5b498ccf611a1e000564f45268dbf301e0b2b08c984dcecc6513f6e", ) + +def kotlin_repositories( + kotlin_release_version=KOTLIN_CURRENT_RELEASE +): + """Call this in the WORKSPACE file to setup the Kotlin rules. + + Args: + kotlin_release_version: The kotlin compiler release version. If this is not set the latest release version is + chosen by default. + """ + _maven_dependencies() + _compiler_repositories(kotlin_release_version) diff --git a/kotlin/toolchains.bzl b/kotlin/internal/toolchains.bzl index c61c8ce..01e07bf 100644 --- a/kotlin/toolchains.bzl +++ b/kotlin/internal/toolchains.bzl @@ -11,14 +11,9 @@ # 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:utils.bzl", - _utils = "utils", -) -load( - "//kotlin/internal:kt.bzl", - _kt = "kt", -) + +load("//kotlin/internal/common:common.bzl", _common="common") +load("//kotlin/internal:defs.bzl", _TOOLCHAIN_TYPE="TOOLCHAIN_TYPE", _KT_COMPILER_REPO="KT_COMPILER_REPO") """Kotlin Toolchains @@ -43,7 +38,7 @@ register_toolchains("//:custom_toolchain") ``` """ -_KT_COMPILER_REPO="com_github_jetbrains_kotlin" + # The toolchain rules are not made private, at least the jvm ones so that they may be introspected in Intelij. _common_attrs = { @@ -114,7 +109,7 @@ _kt_jvm_attrs = dict(_common_attrs.items() + { def _kotlin_toolchain_impl(ctx): toolchain = dict( - label = _utils.restore_label(ctx.label), + label = _common.restore_label(ctx.label), language_version = ctx.attr.language_version, api_version = ctx.attr.api_version, coroutines = ctx.attr.coroutines, @@ -149,6 +144,10 @@ Args: coroutines: the -Xcoroutines flag, enabled by default as it's considered production ready 1.2.0 onward. """ +def kt_register_toolchains(): + """This macro registers all of the default toolchains.""" + native.register_toolchains("@io_bazel_rules_kotlin//kotlin/internal:default_toolchain") + def define_kt_toolchain( name, language_version=None, @@ -172,7 +171,30 @@ def define_kt_toolchain( ) native.toolchain( name = name, - toolchain_type = _kt.defs.TOOLCHAIN_TYPE, + toolchain_type = _TOOLCHAIN_TYPE, toolchain = impl_name, visibility = ["//visibility:public"] ) + +def _kt_toolchain_ide_info_impl(ctx): + tc=ctx.toolchains[_TOOLCHAIN_TYPE] + info = struct( + label = tc.label, + common = struct( + language_version = tc.language_version, + api_version = tc.api_version, + coroutines = tc.coroutines + ), + jvm = struct( + jvm_target = tc.jvm_target, + ) + ) + ctx.actions.write(ctx.outputs.ide_info, info.to_json()) + return [DefaultInfo(files=depset([ctx.outputs.ide_info]))] + +kt_toolchain_ide_info = rule( + outputs = {"ide_info": "kt_toolchain_ide_info.json"}, + toolchains = [_TOOLCHAIN_TYPE], + implementation = _kt_toolchain_ide_info_impl, +) + diff --git a/kotlin/internal/utils.bzl b/kotlin/internal/utils.bzl deleted file mode 100644 index c141584..0000000 --- a/kotlin/internal/utils.bzl +++ /dev/null @@ -1,175 +0,0 @@ -# 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 = "kt", -) - -# MISC UTILS ################################################################################################################################################### -def _restore_label(l): - lbl = l.workspace_root - if lbl.startswith("external/"): - lbl = lbl.replace("external/", "@") - return lbl + "//" + l.package + ":" + l.name - -def _derive_module_name(ctx): - module_name=getattr(ctx.attr, "module_name", "") - if module_name == "": - module_name = (ctx.label.package.lstrip("/").replace("/","_") + "-" + ctx.label.name.replace("/", "_")) - return module_name - -def _partition_srcs(srcs): - kt_srcs = [] - java_srcs = [] - src_jars = [] - - for f in srcs: - if f.path.endswith(".kt"): - kt_srcs.append(f) - elif f.path.endswith(".java"): - java_srcs.append(f) - elif f.path.endswith(".srcjar"): - src_jars.append(f) - - kt = depset(kt_srcs) - java = depset(java_srcs) - - return struct ( - kt = kt, - java = java, - all_srcs = kt + java, - src_jars = depset(src_jars) - ) -# RESOURCE JARS ################################################################################################################################################ -_CONVENTIONAL_RESOURCE_PATHS = [ - "src/main/resources", - "src/test/resources", -] - -def _adjust_resources_path_by_strip_prefix(path, resource_strip_prefix): - if not path.startswith(resource_strip_prefix): - fail("Resource file %s is not under the specified prefix to strip" % path) - - clean_path = path[len(resource_strip_prefix):] - return resource_strip_prefix, clean_path - -def _adjust_resources_path_by_default_prefixes(path): - for cp in _CONVENTIONAL_RESOURCE_PATHS: - dir_1, dir_2, rel_path = path.partition(cp) - if rel_path: - return dir_1 + dir_2, rel_path - return "", path - -def _adjust_resources_path(path, resource_strip_prefix): - if resource_strip_prefix: - return _adjust_resources_path_by_strip_prefix(path,resource_strip_prefix) - else: - return _adjust_resources_path_by_default_prefixes(path) - -def _add_resources_cmd(ctx): - res_cmd = [] - for f in ctx.files.resources: - c_dir, res_path = _adjust_resources_path(f.short_path, ctx.attr.resource_strip_prefix) - target_path = res_path - if target_path[0] == "/": - target_path = target_path[1:] - line = "{target_path}={c_dir}{res_path}\n".format( - res_path=res_path, - target_path=target_path, - c_dir=c_dir) - res_cmd.extend([line]) - return "".join(res_cmd) - -def _build_resourcejar_action(ctx): - resources = _add_resources_cmd(ctx) - resources_jar_output = ctx.actions.declare_file(ctx.label.name + "-resources.jar") - zipper_arg_path = ctx.actions.declare_file("%s_resources_zipper_args" % ctx.label.name) - ctx.file_action(zipper_arg_path, resources) - cmd = """ -rm -f {resources_jar_output} -{zipper} c {resources_jar_output} @{path} -""".format( - path=zipper_arg_path.path, - resources_jar_output=resources_jar_output.path, - zipper=ctx.executable._zipper.path, - ) - ctx.action( - mnemonic="KotlinZipResourceJar", - inputs=ctx.files.resources + [ctx.executable._zipper,zipper_arg_path], - outputs=[resources_jar_output], - command=cmd, - progress_message="Creating intermediate resource jar %s" % ctx.label, - arguments=[] - ) - return resources_jar_output -# PACKAGE JARS ################################################################################################################################################# -def _fold_jars_action(ctx, rule_kind, output_jar, input_jars): - args=[ - "--normalize", - "--compression", - "--deploy_manifest_lines", - "Target-Label: %s" % str(ctx.label), - "Injecting-Rule-Kind: %s" % rule_kind, - "--output", output_jar.path - ] - for i in input_jars: - args += ["--sources", i.path] - ctx.action( - mnemonic = "KotlinFoldOutput", - inputs = input_jars, - outputs = [output_jar], - executable = ctx.executable._singlejar, - arguments = args, - progress_message="Merging Kotlin output jar " + output_jar.short_path - ) - -# JVM LAUNCH SCRIPTS ########################################################################################################################################### -def _write_launcher_action(ctx, rjars, main_class, jvm_flags, args="", wrapper_preamble=""): - """Macro that writes out a launcher script shell script. - Args: - rjars: All of the runtime jars required to launch this java target. - main_class: the main class to launch. - jvm_flags: The flags that should be passed to the jvm. - args: Args that should be passed to the Binary. - """ - classpath = ":".join(["${RUNPATH}%s" % (j.short_path) for j in rjars.to_list()]) - jvm_flags = " ".join([ctx.expand_location(f, ctx.attr.data) for f in jvm_flags]) - template = ctx.attr._java_stub_template.files.to_list()[0] - - ctx.actions.expand_template( - template = template, - output = ctx.outputs.executable, - substitutions = { - "%classpath%": classpath, - "%java_start_class%": main_class, - "%javabin%": "JAVABIN=${RUNPATH}" + ctx.executable._java.short_path, - "%jvm_flags%": jvm_flags, - "%set_jacoco_metadata%": "", - "%workspace_prefix%": ctx.workspace_name + "/", - }, - is_executable = True, - ) - -# EXPORT ####################################################################################################################################################### -utils = struct( - actions = struct( - build_resourcejar = _build_resourcejar_action, - fold_jars = _fold_jars_action, - write_launcher = _write_launcher_action, - ), - restore_label = _restore_label, - derive_module_name = _derive_module_name, - partition_srcs = _partition_srcs -) diff --git a/kotlin/kotlin.bzl b/kotlin/kotlin.bzl index f9920af..7bad54c 100644 --- a/kotlin/kotlin.bzl +++ b/kotlin/kotlin.bzl @@ -1,4 +1,4 @@ -# Copyright 2018 The Bazel Authors. All rights reserved. +# Copyright 2017 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. @@ -11,370 +11,12 @@ # 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. -"""Kotlin Rules - -### Setup - -Add the following snippet to your `WORKSPACE` file: - -```bzl -git_repository( - name = "io_bazel_rules_kotlin", - remote = "https://github.com/bazelbuild/rules_kotlin.git", - commit = "<COMMIT_HASH>", -) -load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kotlin_repositories", "kt_register_toolchains") -kotlin_repositories(kotlin_release_version = "1.2.21") -kt_register_toolchains() -``` - -To enable persistent worker support, add the following to the appropriate `bazelrc` file: - -``` -build --strategy=KotlinCompile=worker -test --strategy=KotlinCompile=worker -``` - - -### Standard Libraries - -The Kotlin libraries that are bundled in a kotlin release should be used with the rules, the mandatory standard libraries are added implicetly. After enabling -the repository the following Kotlin Libraries are also made available from the workspace `com_github_jetbrains_kotlin`: - -* `kotlin-test`, -* `kotlin-reflect`. - -So if you needed to add reflect as a dep use the following label `@com_github_jetbrains_kotlin//:kotlin-reflect`. - -### Mixed Mode compilation - -The JVM rules can compile both Java and Kotlin sources. The Java compiler wrapper is not optimized or persistent and does not have the features found in the -native java rules. This mode is usefull for migrating a package to Kotlin over time. - -### Annotation Processing - -Annotation processing works just as it does in Java, plugins are declared via a [`java_plugin`](https://docs.bazel.build/versions/master/be/java.html#java_plugin) -and may also be inherited from a `java_library` via the `exported_plugins` attribute. Annotation work in mixed-mode compilation and the Kotlin compiler take -care of processing both aspects. - -An example which can be found under `//examples/dagger`: - -```bzl -java_plugin( - name = "dagger_plugin", - deps = [ - "@dagger_compiler//jar", - "@guava//jar", - "@dagger_producers//jar", - "@dagger//jar", - "@javax_inject//jar" - ], - processor_class = "dagger.internal.codegen.ComponentProcessor" -) - -java_library( - name = "dagger_lib", - exports = [ - "@javax_inject//jar", - "@dagger//jar", - ], - exported_plugins = ["dagger_plugin"] -) - -kt_jvm_binary( - name = "dagger", - srcs = glob(["src/**"]), - main_class = "coffee.CoffeeApp", - deps = [":dagger_lib"], -) -``` -""" -# This file is the main import -- it shouldn't grow out of hand the reason it contains so much allready is due to the limitations of skydoc. - -######################################################################################################################## -# Common Definitions -######################################################################################################################## - -load( - "//kotlin/internal:kt.bzl", - _kt = "kt", -) -# struct can't be used till skydoc is removed -load( - "//kotlin/internal:plugins.bzl", - _kt_jvm_plugin_aspect="kt_jvm_plugin_aspect", -) -# struct can't be used till skydoc is removed -load( - "//kotlin/internal:rules.bzl", - _kt_jvm_binary_impl = "kt_jvm_binary_impl", - _kt_jvm_import_impl = "kt_jvm_import_impl", - _kt_jvm_junit_test_impl = "kt_jvm_junit_test_impl", - _kt_jvm_library_impl = "kt_jvm_library_impl", -) -load("//kotlin:kotlin_releases.bzl", "KOTLIN_CURRENT_RELEASE") -load( - "//kotlin:kotlin_compiler_repositories.bzl", - _kotlin_compiler_repository = "kotlin_compiler_repositories", -) -load("//third_party/jvm:workspace.bzl", _maven_dependencies="maven_dependencies") - -######################################################################################################################## -# Rule Attributes -######################################################################################################################## -_implicit_deps = { - "_kotlin_toolchain": attr.label_list( - default = [ - Label("@io_bazel_rules_kotlin//kotlin:kt_toolchain_ide_info"), - ], - cfg="host", - allow_files = False, - ), - "_singlejar": attr.label( - executable = True, - cfg = "host", - default = Label("@bazel_tools//tools/jdk:singlejar"), - allow_files = True, - ), - "_zipper": attr.label( - executable = True, - cfg = "host", - default = Label("@bazel_tools//tools/zip:zipper"), - allow_files = True, - ), - "_java": attr.label( - executable = True, - cfg = "host", - default = Label("@bazel_tools//tools/jdk:java"), - allow_files = True, - ), - "_java_stub_template": attr.label( - cfg = "host", - default = Label("@kt_java_stub_template//file"), - ), -} - -_common_attr = dict(_implicit_deps.items() + { - "srcs": attr.label_list( - default = [], - allow_files = [".srcjar", ".kt", ".java"], - ), - "deps": attr.label_list( - aspects = [_kt_jvm_plugin_aspect], - providers=[ - [JavaInfo], - ], - allow_files = False), - "runtime_deps": attr.label_list(default = [], allow_files=False), - "resources": attr.label_list( - default = [], - allow_files = True, - ), - "resource_strip_prefix": attr.string(default = ""), - "resource_jars": attr.label_list(default = []), - "data": attr.label_list( - allow_files = True, - cfg = "data", - ), - "plugins": attr.label_list( - default = [], - aspects = [_kt_jvm_plugin_aspect], - ), - "module_name": attr.string(), -}.items()) - -_runnable_common_attr = dict(_common_attr.items() + { - "jvm_flags": attr.string_list( - default = [], - ), -}.items()) - -######################################################################################################################## -# Outputs: All the outputs produced by the various rules are modelled here. -######################################################################################################################## -_common_outputs = dict( - jar = "%{name}.jar", - jdeps = "%{name}.jdeps", - # The params file, declared here so that validate it can be validated for testing. -# jar_2_params = "%{name}.jar-2.params", - srcjar = "%{name}-sources.jar", -) - -_binary_outputs = dict(_common_outputs.items() + { -}.items()) - -######################################################################################################################## -# Repositories and Toolchains -######################################################################################################################## -def kotlin_repositories( - kotlin_release_version=KOTLIN_CURRENT_RELEASE -): - """Call this in the WORKSPACE file to setup the Kotlin rules. - - Args: - kotlin_release_version: The kotlin compiler release version. If this is not set the latest release version is - chosen by default. - """ - _maven_dependencies() - _kotlin_compiler_repository(kotlin_release_version) - -def kt_register_toolchains(): - """register all default toolchains""" - native.register_toolchains(_kt.defs.DEFAULT_TOOLCHAIN) - -######################################################################################################################## -# Simple Rules: -######################################################################################################################## -kt_jvm_library = rule( - attrs = dict(_common_attr.items() + { - "exports": attr.label_list(default = [], providers=[JavaInfo]), - "neverlink": attr.bool(default=False), - }.items()), - outputs = _common_outputs, - toolchains = [_kt.defs.TOOLCHAIN_TYPE], - implementation = _kt_jvm_library_impl, - provides = [JavaInfo, _kt.info.KtInfo] -) - -"""This rule compiles and links Kotlin and Java sources into a .jar file. -Args: - srcs: The list of source files that are processed to create the target, this can contain both Java and Kotlin files. Java analysis occurs first so Kotlin - classes may depend on Java classes in the same compilation unit. - exports: Exported libraries. - - Deps listed here will be made available to other rules, as if the parents explicitly depended on these deps. - This is not true for regular (non-exported) deps. - resources: A list of data files to include in a Java jar. - resource_strip_prefix: The path prefix to strip from Java resources, files residing under common prefix such as `src/main/resources` or `src/test/resources` - will have stripping applied by convention. - resource_jars: Set of archives containing Java resources. If specified, the contents of these jars are merged into the output jar. - runtime_deps: Libraries to make available to the final binary or test at runtime only. Like ordinary deps, these will appear on the runtime classpath, but - unlike them, not on the compile-time classpath. - data: The list of files needed by this rule at runtime. See general comments about `data` at [Attributes common to all build rules](https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes). - deps: A list of dependencies of this rule.See general comments about `deps` at [Attributes common to all build rules](https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes). - module_name: The name of the module, if not provided the module name is derived from the label. --e.g., `//some/package/path:label_name` is translated to - `some_package_path-label_name`. - neverlink: If true only use this library for compilation and not at runtime. -""" - -kt_jvm_binary = rule( - attrs = dict(_runnable_common_attr.items() + { - "main_class": attr.string(mandatory = True) - }.items()), - executable = True, - outputs = _binary_outputs, - toolchains = [_kt.defs.TOOLCHAIN_TYPE], - implementation = _kt_jvm_binary_impl, -) - -"""Builds a Java archive ("jar file"), plus a wrapper shell script with the same name as the rule. The wrapper shell script uses a classpath that includes, -among other things, a jar file for each library on which the binary depends. - -**Note:** This rule does not have all of the features found in [`java_binary`](https://docs.bazel.build/versions/master/be/java.html#java_binary). It is -appropriate for building workspace utilities. `java_binary` should be preferred for release artefacts. - -Args: - main_class: Name of class with main() method to use as entry point. - jvm_flags: A list of flags to embed in the wrapper script generated for running this binary. Note: does not yet support make variable substitution. -""" - -kt_jvm_test = rule( - attrs = dict(_runnable_common_attr.items() + { - "_bazel_test_runner": attr.label( - default = Label("@bazel_tools//tools/jdk:TestRunner_deploy.jar"), - allow_files = True, - ), - "friends": attr.label_list( - default = [], - providers = [JavaInfo] - ), - "test_class": attr.string(), - "main_class": attr.string(default="com.google.testing.junit.runner.BazelTestRunner"), - }.items()), - executable = True, - outputs = _binary_outputs, - test = True, - toolchains = [_kt.defs.TOOLCHAIN_TYPE], - implementation = _kt_jvm_junit_test_impl, -) - -"""Setup a simple kotlin_test. - -**Notes:** -* The kotlin test library is not added implicitly, it is available with the label `@com_github_jetbrains_kotlin//:kotlin-test`. - -Args: - test_class: The Java class to be loaded by the test runner. - friends: A single Kotlin dep which allows the test code access to internal members. Currently uses the output jar of - the module -- i.e., exported deps won't be included. -""" - -kt_jvm_import = rule( - attrs = { - "jars": attr.label_list( - allow_files = True, - mandatory = True, - cfg = "target", - ), - "srcjar": attr.label( - allow_single_file = True, - cfg = "target", - ), - "runtime_deps": attr.label_list( - default = [], - mandatory = False, - providers = [JavaInfo] - ) - }, - implementation = _kt_jvm_import_impl, - provides = [JavaInfo, _kt.info.KtInfo] -) - -# The pairing of src and class is used by intellij to attatch sources, this is picked up via the kt provider attribute. -# -# once current format and semantics are finalized add runtime_deps, exports, data, neverlink, testonly. -# * runtime_deps should accept JavaInfo's (this includes KotlinInfo) and maven_jar filegroups. -# * exports should only accept JavaInfo's (this include KotlinInfo) but not filegroup. The jars attribute takes care of importing the jars without generating -# ijars. -"""(experimental) Import Kotlin jars. - -**Status:** This rule is not a counterpart to `java_import`. The current purpose for this rule is to import a kotlin jar without creating ijars. It will -eventually [be replaced](https://github.com/bazelbuild/rules_kotlin/issues/4) with `java_import`. If there is a need for expanding this rule we can instead -create a utility macro that delegates to this. - -## examples - -```bzl -# Old style usage -- reference file groups, do not used this. -kt_jvm_import( - name = "kodein", - jars = [ - "@com_github_salomonbrys_kodein_kodein//jar:file", - "@com_github_salomonbrys_kodein_kodein_core//jar:file" - ] -) - -# This style will pull in the transitive runtime dependencies of the targets as well. -kt_jvm_import( - name = "kodein", - jars = [ - "@com_github_salomonbrys_kodein_kodein//jar", - "@com_github_salomonbrys_kodein_kodein_core//jar" - ] -) - -# Import a single kotlin jar. -kt_jvm_import( - name = "kotlin-runtime", - jars = ["lib/kotlin-runtime.jar"], - srcjar = "lib/kotlin-runtime-sources.jar" -) -``` - -Args: - jars: The jars listed here are equavalent to an export attribute. The label should be either to a single class jar, or multiple filegroup labels. When the - labels is a file_provider it should follow the conventions used in repositories generated by the maven_jar rule --i.e., the rule expects a file_provider - with a single class jar and a single source jar. a source jar is recognized by the suffix `-sources.jar`. - srcjar: The sources for the class jar. This should be set when importing a single class jar. - runtime_deps: Additional runtime deps. -""" +load("//kotlin/internal/repositories:repositories.bzl", "kotlin_repositories") +load("//kotlin/internal:toolchains.bzl", "kt_register_toolchains") + +load("//kotlin/internal/jvm:jvm.bzl", + "kt_jvm_binary", + "kt_jvm_library", + "kt_jvm_test", + "kt_jvm_import", +)
\ No newline at end of file |