pubref / rules_kotlin

Bazel rules for Kotlin
Other
159 stars 20 forks source link
bazel bazel-rules java kotlin
Bazel Kotlin

Kotlin Rules for Bazel

Build Status

Build Kotlin source with with Bazel.

Rule Description
kotlin_repositories Load workspace dependencies
kotlin_library Build a java library from kotlin source
kotlin_binary Build a java binary from kotlin source
kotlin_android_library Build an android library from kotlin source
kotlin_test Run a kotlin test

Note: Bazel 0.7.0 or higher is required for rules_kotlin 0.5.0.

Workspace rules

Add the following to your WORKSPACE file:

git_repository(
    name = "org_pubref_rules_kotlin",
    remote = "https://github.com/pubref/rules_kotlin.git",
    tag = "v0.5.0", # update as needed
)

load("@org_pubref_rules_kotlin//kotlin:rules.bzl", "kotlin_repositories")

kotlin_repositories()

This will fetch a kotlin release (currently 1.1.4-3) and load a number of dependencies related to dagger (used to build the KotlinCompiler bazel worker).

You can override kotlin release via the com_github_jetbrains_kotlin_url, com_github_jetbrains_kotlin_sha256 options and various dependencies loaded in the kotlin_repositories rule via the omit_* options; see the source file for details.

BUILD rules

Add the following to your BUILD file:

load("@org_pubref_rules_kotlin//kotlin:rules.bzl", "kotlin_library")

kotlin_library

Example:

kotlin_library(
    name = "my_kotlin_lib",
    srcs = ["kotlin_source_file.kt"],
    deps = [":some_other_kotlin_library_rule"],
    java_deps = [":some_other_java_library_rule", "@another_maven_jar//jar"],
)

Use the deps attribute to name other kotlin_library targets as jar providers for this rule. Use the java_deps attribute to name other java_library or java_import targets (to expose traditional java classes in your kotlin source).

To compile a set of kotlin sources files with the kotlinc tool and emit the corresponding jar file, use:

$ bazel build :my_kotlin_lib
Target :my_kotlin_lib up-to-date:
  bazel-bin/.../my_kotlin_lib.jar

To use the output of a kotlin_library as input to a java_library rule (and make your compiled kotlin classes available to your traditional java source files), name it as a dependency using the deps attribute, just as you would any other java_library target. The name of this target must be of the form {kotlin_library_target_name}_kt. For example, to use the :my_kotlin_lib in an android_binary target, the name would be :my_kotlin_lib_kt, such as:

android_binary(
   name = "foo",
   deps = [
       ":my_kotlin_lib_kt`,
   ]
)

kotlin_library attributes

Name Type Description
srcs label_list Kotlin source files *.kt
deps label_list List of kotlin_library targets
java_deps label_list List of java provider targets (java_library, java_import, ...)
android_deps label_list List of android provider targets (android_library)
jars label_list List of jar file targets (*.jar)
x_opts string_list List of additional -X options to kotlinc
plugin_opts string_dict List of additional -P options to kotlinc

kotlin_binary

A kotlin_binary macro takes the same arguments as a kotlin_library, plus a required main_class argument (the name of the compiled kotlin class to run, in java package notation). This class should have a fun main(...) entrypoint. Example:

kotlin_binary(
    name = "main_kt",
    main_class = "my.project.MainKt",
    srcs = ["main.kt"],
    deps = [":my_kotlin_lib"]
    java_deps = [":javalib"]
)

To create a self-contained executable jar, invoke the implicit _deploy.jar target. For example:

$ bazel build :main_kt_deploy.jar
Target :main_kt_deploy.jar up-to-date:
  bazel-bin/.../main_kt_deploy.jar
$ java -jar ./bazel-bin/.../main_kt_deploy.jar

The kotlin-runtime.jar is implicitly included by the kotlin_binary rule.

kotlin_binary attributes

Includes all kotlin_library attributes as well as:

Name Type Description
main_class string Main class to run with the kotlin_binary rule

kotlin_android_library

A kotlin_android_library macro takes mostly the same arguments as a kotlin_library, plus some Android specific arguments like aar_deps, resource_files, custom_package, manifest, etc. An example with combined source and resource:

PACKAGE = "com.company.app"
MANIFEST = "AndroidManifest.xml"

kotlin_android_library(
    name = "src",
    srcs = glob(["src/**/*.kt"]),
    custom_package = PACKAGE,
    manifest = MANIFEST,
    resource_files = glob(["res/**/*"]),
    java_deps = [
        "@com_squareup_okhttp3_okhttp//jar",
        "@com_squareup_okio_okio//jar",
    ],
    aar_deps = [
        "@androidsdk//com.android.support:appcompat-v7-25.3.1",
        "@androidsdk//com.android.support:cardview-v7-25.3.1",
        "@androidsdk//com.android.support:recyclerview-v7-25.3.1",
    ],
)

android_binary(
    name = "app",
    custom_package = PACKAGE,
    manifest = MANIFEST,
    deps = [
        ":src",
    ],
)

If you prefer to separate your source files and resource files in different Bazel rules (for example the resource files are also used by java android_library rules), you can do so as example:

PACKAGE = "com.company.app"
MANIFEST = "AndroidManifest.xml"

android_library(
    name = "res",
    custom_package = PACKAGE,
    manifest = MANIFEST,
    resource_files = glob(["res/**/*"]),
    aar_deps = [
        "@androidsdk//com.android.support:appcompat-v7-25.3.1",
        "@androidsdk//com.android.support:cardview-v7-25.3.1",
        "@androidsdk//com.android.support:recyclerview-v7-25.3.1",
    ],
)

android_library(
    name = "java",
    srcs = glob(["src/**/*.java"]),
    deps = [
        ":res",
        # And other depedencies
    ]
)

kotlin_android_library(
    name = "kt",
    srcs = glob(["src/**/*.kt"]),
    aar_deps = [
        "@androidsdk//com.android.support:appcompat-v7-25.3.1",
        "@androidsdk//com.android.support:cardview-v7-25.3.1",
        "@androidsdk//com.android.support:recyclerview-v7-25.3.1",
    ],
    android_deps = [
        ":res",
    ]
)

android_binary(
    name = "app",
    custom_package = PACKAGE,
    manifest = MANIFEST,
    deps = [
        ":java",
        ":kt",
        ":res",
    ],
)

Please note that if you want to use R class in your Kotlin code, your kotlin_android_library rule need to either have the resource_files and related arguments, or have the resource rule in android_deps.

kotlin_android_library attributes

Includes all kotlin_library attributes as well as:

Name Type Description
aar_deps label_list List of AAR library targets

And also android_library arguments.

kotlin_test

The kotlin_test rule is nearly identical the kotlin_binary rule (other than calling java_test internally rather than java_binary).

kotlin_test(
    name = "main_kt_test",
    test_class = "examples.helloworld.MainKtTest",
    srcs = ["MainKtTest.kt"],
    size = "small",
    deps = [
        ":rules",
    ],
    java_deps = [
        "@junit4//jar",
    ],
)
$ bazel test :main_kt_test.jar

The kotlin-test.jar is implicitly included by the kotlin_test rule.

kotlin_compile

TL;DR; You most likely do not need to interact with the kotlin_compile rule directly.

The kotlin_compile rule runs the kotlin compiler to generate a .jar file from a list of kotlin source files. The kotlin_library rule calls this internally and then makes the jarfile available to other java rules via a java_import rule.

Summary

That's it! Hopefully these rules with make it easy to mix kotlin and traditional java code in your projects and take advantage of bazel's approach to fast, repeatable, and reliable builds.

Note: Consider rules_maven for handling transitive maven dependencies with your java/kotlin projects.

Examples

To run the examples in this repository, clone the repo:

$ git clone https://github.com/pubref/rules_kotlin
$ cd rules_kotlin
$ bazel query //... --output label_kind
$ bazel run examples/helloworld:main_kt
$ bazel run examples/helloworld:main_java
$ bazel test examples/helloworld:main_test
$ bazel test examples/helloworld:main_kt_test

TODO

  1. Proper data and runfiles support.
  2. kapt support.
  3. Incremental compilation.