Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/bazelbuild/rules_kotlin

Bazel rules for Kotlin
https://github.com/bazelbuild/rules_kotlin

bazel bazel-rules kotlin

Last synced: 6 days ago
JSON representation

Bazel rules for Kotlin

Awesome Lists containing this project

README

        

# Bazel Kotlin Rules

[![Build Status](https://badge.buildkite.com/a8860e94a7378491ce8f50480e3605b49eb2558cfa851bbf9b.svg)](https://buildkite.com/bazel/kotlin-postsubmit)

### Releases




For more information about release and changelogs please see [Changelog](CHANGELOG.md) or refer to the [Github Releases](https://github.com/bazelbuild/rules_kotlin/releases) page.

# `rules_kotlin` Bazel Compatibility
- HEAD: `6`, `7`
- [Release 1.9](https://github.com/bazelbuild/rules_kotlin/releases/tag/v1.9.1): `6`, `7`
- [Release 1.8](https://github.com/bazelbuild/rules_kotlin/releases/tag/v1.8.1): `5`, `6`
- [Release 1.7](https://github.com/bazelbuild/rules_kotlin/releases/tag/v1.7.1): `4`, `5`, `6`

# Overview

**rules_kotlin** supports the basic paradigm of `*_binary`, `*_library`, `*_test` of other Bazel
language rules. It also supports `jvm`, `android`, and `js` flavors, with the prefix `kt_jvm`
and `kt_android` typically applied to the rules.

Support for kotlin's -Xfriend-paths via the `associates=` attribute in the jvm allow access to
`internal` members.

Also, `kt_jvm_*` rules support the following standard `java_*` rules attributes:
* `data`
* `resource_jars`
* `runtime_deps`
* `resources`
* `resources_strip_prefix`
* `exports`

Android rules also support custom_package for `R.java` generation, `manifest=`, `resource_files`, etc.

Other features:
* Persistent worker support.
* Mixed-Mode compilation (compile Java and Kotlin in one pass).
* Configurable Kotlinc distribution and version
* Configurable Toolchain
* Support for all recent major Kotlin releases.

Javascript is reported to work, but is not as well maintained (at present)

# Documentation

Generated API documentation is available at
[https://bazelbuild.github.io/rules_kotlin/kotlin](https://bazelbuild.github.io/rules_kotlin/kotlin).

# Quick Guide

## `WORKSPACE`
In the project's `WORKSPACE`, declare the external repository and initialize the toolchains, like
this:

```python
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

rules_kotlin_version = "1.9.0"
rules_kotlin_sha = "5766f1e599acf551aa56f49dab9ab9108269b03c557496c54acaf41f98e2b8d6"
http_archive(
name = "rules_kotlin",
urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/v%s/rules_kotlin-v%s.tar.gz" % (rules_kotlin_version, rules_kotlin_version)],
sha256 = rules_kotlin_sha,
)

load("@rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories")
kotlin_repositories() # if you want the default. Otherwise see custom kotlinc distribution below

load("@rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")
kt_register_toolchains() # to use the default toolchain, otherwise see toolchains below
```

## `BUILD` files

In your project's `BUILD` files, load the Kotlin rules and use them like so:

```python
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")

kt_jvm_library(
name = "package_name",
srcs = glob(["*.kt"]),
deps = [
"//path/to/dependency",
],
)
```

## Custom toolchain

To enable a custom toolchain (to configure language level, etc.)
do the following. In a `/BUILD.bazel` file define the following:

```python
load("@rules_kotlin//kotlin:core.bzl", "define_kt_toolchain")

define_kt_toolchain(
name = "kotlin_toolchain",
api_version = KOTLIN_LANGUAGE_LEVEL, # "1.1", "1.2", "1.3", "1.4", "1.5" "1.6", "1.7", "1.8", or "1.9"
jvm_target = JAVA_LANGUAGE_LEVEL, # "1.6", "1.8", "9", "10", "11", "12", "13", "15", "16", "17", "18", "19", "20" or "21"
language_version = KOTLIN_LANGUAGE_LEVEL, # "1.1", "1.2", "1.3", "1.4", "1.5" "1.6", "1.7", "1.8", or "1.9"
)
```

and then in your `WORKSPACE` file, instead of `kt_register_toolchains()` do

```python
register_toolchains("//:kotlin_toolchain")
```

## Custom `kotlinc` distribution (and version)

To choose a different `kotlinc` distribution (1.3 and 1.4 variants supported), do the following
in your `WORKSPACE` file (or import from a `.bzl` file:

```python
load("@rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories", "kotlinc_version")

kotlin_repositories(
compiler_release = kotlinc_version(
release = "1.6.21", # just the numeric version
sha256 = "632166fed89f3f430482f5aa07f2e20b923b72ef688c8f5a7df3aa1502c6d8ba"
)
)
```

## Third party dependencies
_(e.g. Maven artifacts)_

Third party (external) artifacts can be brought in with systems such as [`rules_jvm_external`](https://github.com/bazelbuild/rules_jvm_external) or [`bazel_maven_repository`](https://github.com/square/bazel_maven_repository) or [`bazel-deps`](https://github.com/johnynek/bazel-deps), but make sure the version you use doesn't naively use `java_import`, as this will cause bazel to make an interface-only (`ijar`), or ABI jar, and the native `ijar` tool does not know about kotlin metadata with respect to inlined functions, and will remove method bodies inappropriately. Recent versions of `rules_jvm_external` and `bazel_maven_repository` are known to work with Kotlin.

# Development Setup Guide
As of 1.5.0, to use the rules directly from the rules_kotlin workspace (i.e. not the release artifact)
require the use of `release_archive` repository. This repository will build and configure the current
workspace to use `rules_kotlin` in the same manner as the released binary artifact.

In the project's `WORKSPACE`, change the setup:

```python

# Use local check-out of repo rules (or a commit-archive from github via http_archive or git_repository)
local_repository(
name = "rules_kotlin",
path = "../path/to/rules_kotlin_clone/",
)

load("@rules_kotlin//kotlin:dependencies.bzl", "kt_download_local_dev_dependencies")

kt_download_local_dev_dependencies()

load("@rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories", "versions")

kotlin_repositories()

load("@rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")

kt_register_toolchains()
```

To use rules_kotlin from head without cloning the repository, (caveat emptor, of course), change the
rules to this:

```python
# Download master or specific revisions
http_archive(
name = "rules_kotlin",
strip_prefix = "rules_kotlin-master",
urls = ["https://github.com/bazelbuild/rules_kotlin/archive/refs/heads/master.zip"],
)

load("@rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories")

kotlin_repositories()

load("@rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")

kt_register_toolchains()
```

# Debugging native actions

To attach debugger and step through native action code when using local checkout of rules_kotlin repo :

1. Open `rules_kotlin` project in Android Studio, using existing `.bazelproject` file as project view.
2. In terminal, build the kotlin target you want to debug, using the subcommand option, ex: `bazel build //lib/mylib:main_kt -s`. You can also use `bazel aquery` to get this info.
3. Locate the subcommand for the kotlin action you want to debug, let's say `KotlinCompile`. Note: If you don't see it, target rebuild may have been skipped (in this case `touch` one of the source .kt file to trigger rebuild).
4. Export `REPOSITORY_NAME` as specified in action env, ex : `export REPOSITORY_NAME=rules_kotlin`
5. Copy the command line, ex : `bazel-out/darwin_arm64-opt-exec-2B5CBBC6/bin/external/rules_kotlin/src/main/kotlin/build '--flagfile=bazel-out/darwin_arm64-fastbuild/bin/lib/mylib/main_kt-kt.jar-0.params'`
6. Change directory into the [execRoot](https://bazel.build/remote/output-directories#layout-diagram), normally `bazel-MYPROJECT`, available via `bazel info | grep execution_root`.
7. Add `--debug=5005` to command line to make the action wait for a debugger to attach, ex: `bazel-out/darwin_arm64-opt-exec-2B5CBBC6/bin/external/rules_kotlin/src/main/kotlin/build --debug=5005 '--flagfile=bazel-out/darwin_arm64-fastbuild/bin/lib/mylib/main_kt-kt.jar-0.params'`. Note: if command invokes `java` toolchain directly, use `-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005` instead.
8. You should see in output that action is waiting for debugger. Use a default `Remote JVM Debug` configuration in Android Studio, set breakpoint in kotlin action java/kt code, and attach debugger. Breakpoints should be hit.

# Kotlin and Java compiler flags

The `kt_kotlinc_options` and `kt_javac_options` rules allows passing compiler flags to kotlinc and javac.

Note: Not all compiler flags are supported in all language versions. When this happens, the rules will fail.

For example you can define global compiler flags by doing:
```python
load("@rules_kotlin//kotlin:core.bzl", "kt_kotlinc_options", "kt_javac_options", "define_kt_toolchain")

kt_kotlinc_options(
name = "kt_kotlinc_options",
x_no_param_assertions = True,
jvm_target = "1.8",
)

kt_javac_options(
name = "kt_javac_options",
warn = "off",
)

define_kt_toolchain(
name = "kotlin_toolchain",
kotlinc_options = "//:kt_kotlinc_options",
javac_options = "//:kt_javac_options",
)
```

You can optionally override compiler flags at the target level by providing an alternative set of `kt_kotlinc_options` or `kt_javac_options` in your target definitions.

Compiler flags that are passed to the rule definitions will be taken over the toolchain definition.

Example:
```python
load("@rules_kotlin//kotlin:core.bzl", "kt_kotlinc_options", "kt_javac_options")
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")

kt_kotlinc_options(
name = "kt_kotlinc_options_for_package_name",
x_no_param_assertions = True,
x_optin = [
"kotlin.Experimental",
"kotlin.ExperimentalStdlibApi",
],
)

kt_javac_options(
name = "kt_javac_options_for_package_name",
warn = "off"
)

kt_jvm_library(
name = "package_name",
srcs = glob(["*.kt"]),
kotlinc_opts = "//:kt_kotlinc_options_for_package_name",
javac_opts = "//:kt_javac_options_for_package_name",
deps = ["//path/to/dependency"],
)
```

Additionally, you can add options for both tracing and timing of the bazel build using the `kt_trace` and `kt_timings` flags, for example:
* `bazel build --define=kt_trace=1`
* `bazel build --define=kt_timings=1`

`kt_trace=1` will allow you to inspect the full kotlinc commandline invocation, while `kt_timings=1` will report the high level time taken for each step.

# KSP (Kotlin Symbol Processing)

KSP is officially supported as of `rules_kotlin` 1.8 and can be declared using the new
`kt_ksp_plugin` rule.

A few things to note:
- As of now `rules_kotlin` only supports KSP plugins that generate Kotlin code.
- KSP is [not yet thread safe](https://github.com/google/ksp/issues/1385) and will likely fail if you are using it in a build that has multiplex workers enabled. To work around this add the following flag to your Bazelrc:
```
build --experimental_worker_max_multiplex_instances=KotlinKsp=1
```

```python
load("@rules_kotlin//kotlin:core.bzl", "kt_ksp_plugin")
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")

kt_ksp_plugin(
name = "moshi-kotlin-codegen",
processor_class = "com.squareup.moshi.kotlin.codegen.ksp.JsonClassSymbolProcessorProvider",
deps = [
"@maven//:com_squareup_moshi_moshi",
"@maven//:com_squareup_moshi_moshi_kotlin",
"@maven//:com_squareup_moshi_moshi_kotlin_codegen",
],
)

kt_jvm_library(
name = "lib",
srcs = glob(["*.kt"]),
plugins = ["//:moshi-kotlin-codegen"],
)
```

To choose a different `ksp_version` distribution,
do the following in your `WORKSPACE` file (or import from a `.bzl` file):

```python
load("@rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories", "ksp_version")

kotlin_repositories(
ksp_compiler_release = ksp_version(
release = "1.8.22-1.0.11",
sha256 = "2ce5a08fddd20ef07ac051615905453fe08c3ba3ce5afa5dc43a9b77aa64507d",
),
)
```

# Kotlin compiler plugins

The `kt_compiler_plugin` rule allows running Kotlin compiler plugins, such as no-arg, sam-with-receiver and allopen.

For example, you can add allopen to your project like this:
```python
load("@rules_kotlin//kotlin:core.bzl", "kt_compiler_plugin")
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")

kt_compiler_plugin(
name = "open_for_testing_plugin",
id = "org.jetbrains.kotlin.allopen",
options = {
"annotation": "plugin.allopen.OpenForTesting",
},
deps = [
"//kotlin/compiler:allopen-compiler-plugin",
],
)

kt_jvm_library(
name = "user",
srcs = ["User.kt"], # The User class is annotated with OpenForTesting
plugins = [
":open_for_testing_plugin",
],
deps = [
":open_for_testing", # This contains the annotation (plugin.allopen.OpenForTesting)
],
)
```

Full examples of using compiler plugins can be found [here](examples/plugin).

## Creating Rule Releases

A new release can be published by just pushing a tag.

Once the tag is pushed, GitHub Actions will build, test, and publish a release to both GitHub releases and the BCR.

A tag can be created and pushed by doing the following:
```
git tag v4.13
git push origin v4.13
```

## Examples

Examples can be found in the [examples directory](https://github.com/bazelbuild/rules_kotlin/tree/master/examples), including usage with Android, Dagger, Node-JS, Kotlin compiler plugins, etc.

# History

These rules were initially forked from [pubref/rules_kotlin](http://github.com/pubref/rules_kotlin), and then re-forked from [bazelbuild/rules_kotlin](http://github.com/bazelbuild/rules_kotlin). They were merged back into this repository in October, 2019.

# License

This project is licensed under the [Apache 2.0 license](LICENSE), as are all contributions

# Contributing

See the [CONTRIBUTING](CONTRIBUTING.md) doc for information about how to contribute to
this project.