Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Kotlin JARs with inlined functions, and an Android Kotlin example app #69

Merged
merged 13 commits into from
Mar 26, 2019
23 changes: 21 additions & 2 deletions .bazelci/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ tasks:
working_directory: examples/android_instrumentation_test
# Android instrumentation tests don't work on Windows yet.
build_targets:
- "//src/main:greeter_app"
- "//src/test:greeter_test_app"
android-local-test-linux:
name: "Android Robolectric test example"
platform: ubuntu1804
Expand All @@ -60,3 +58,24 @@ tasks:
# See https://github.com/bazelbuild/bazel/issues/7809
build_targets:
- "//..."
android-kotlin-linux:
name: "Android Kotlin example"
platform: ubuntu1804
working_directory: examples/android_kotlin_app
build_targets:
- "//:app"
android-kotlin-macos:
name: "Android Kotlin example"
platform: macos
working_directory: examples/android_kotlin_app
build_targets:
- "//:app"
# rules_kotlin does not work on Windows.
# https://github.com/bazelbuild/rules_kotlin/issues/179
# https://github.com/bazelbuild/rules_kotlin/blob/master/.bazelci/presubmit.yml
# android-kotlin-windows:
# name: "Android Kotlin example"
# platform: windows
# working_directory: examples/android_kotlin_app
# build_targets:
# - "//:app"
5 changes: 5 additions & 0 deletions .bazelci/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,9 @@ platforms:
# TODO(jin): fix long paths issue on Windows
# - "//examples:app"
test_targets:
- "--"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does the "--" do?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allows using the target subtraction syntax -//:target

- "//tests/unit/..."
# rules_kotlin is not tested / does not work on Windows.
# https://github.com/bazelbuild/rules_kotlin/issues/179
# https://github.com/bazelbuild/rules_kotlin/blob/master/.bazelci/presubmit.yml
- "-//tests/unit/kotlin/..."
31 changes: 30 additions & 1 deletion WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ maven_install(
use_unsafe_shared_cache = True,
)

maven_install(
name = "kotlin_tests",
artifacts = [
"junit:junit:4.12",
"org.jetbrains.kotlin:kotlin-test:1.3.21",
],
repositories = [
"https://repo1.maven.org/maven2",
],
)

# These artifacts helped discover limitations by the Maven resolver. Each
# artifact listed here *must have* an accompanying issue. We build_test these
# targets to ensure that they remain supported by the rule.
Expand All @@ -104,14 +115,32 @@ maven_install(
],
)

RULES_KOTLIN_VERSION = "da1232eda2ef90d4375e2d1677b32c7ddf09e8a1"

http_archive(
name = "io_bazel_rules_kotlin",
sha256 = "0bbb0e5e536f0c775f37bded59d4f8cfb8556e6c3d926fcc0f58bf3489bff470",
strip_prefix = "rules_kotlin-%s" % RULES_KOTLIN_VERSION,
url = "https://github.com/bazelbuild/rules_kotlin/archive/%s.tar.gz" % RULES_KOTLIN_VERSION,
)

load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kotlin_repositories", "kt_register_toolchains")

kotlin_repositories()

kt_register_toolchains()

BAZEL_SKYLIB_TAG = "0.7.0"

http_archive(
name = "bazel_skylib",
sha256 = "2c62d8cd4ab1e65c08647eb4afe38f51591f43f7f0885e7769832fa137633dcb",
strip_prefix = "bazel-skylib-%s" % BAZEL_SKYLIB_TAG,
url = "https://github.com/bazelbuild/bazel-skylib/archive/%s.tar.gz" % BAZEL_SKYLIB_TAG,
sha256 = "2c62d8cd4ab1e65c08647eb4afe38f51591f43f7f0885e7769832fa137633dcb",
)

load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")

bazel_skylib_workspace()

# End test dependencies
48 changes: 34 additions & 14 deletions coursier.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ load("//:specs.bzl", "parse", "utils")

_BUILD = """
package(default_visibility = ["//visibility:public"])

load("@{repository_name}//:jvm_import.bzl", "jvm_import")

{imports}
"""

Expand Down Expand Up @@ -73,16 +76,17 @@ def _relativize_and_symlink_file(repository_ctx, absolute_path):
# Get the reverse dependencies of an artifact from the Coursier parsed
# dependency tree.
def _get_reverse_deps(coord, dep_tree):
reverse_deps = []
# For all potential reverse dep artifacts,
for maybe_rdep in dep_tree["dependencies"]:
# For all dependencies of this artifact,
for maybe_rdep_coord in maybe_rdep["dependencies"]:
# If this artifact depends on the missing artifact,
if maybe_rdep_coord == coord:
# Then this artifact is an rdep :-)
reverse_deps.append(maybe_rdep)
return reverse_deps
reverse_deps = []
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drive by formatting fix.


# For all potential reverse dep artifacts,
for maybe_rdep in dep_tree["dependencies"]:
# For all dependencies of this artifact,
for maybe_rdep_coord in maybe_rdep["dependencies"]:
# If this artifact depends on the missing artifact,
if maybe_rdep_coord == coord:
# Then this artifact is an rdep :-)
reverse_deps.append(maybe_rdep)
return reverse_deps

# Generate BUILD file with java_import and aar_import for each artifact in
# the transitive closure, with their respective deps mapped to the resolved
Expand Down Expand Up @@ -154,7 +158,10 @@ def generate_imports(repository_ctx, dep_tree, srcs_dep_tree = None):
#
packaging = artifact_relative_path.split(".").pop()
if packaging == "jar":
target_import_string = ["java_import("]
# Regular `java_import` invokes ijar on all JARs, causing some Scala and
# Kotlin compile interface JARs to be incorrect. We replace java_import
# with a simple jvm_import Starlark rule that skips ijar.
target_import_string = ["jvm_import("]
elif packaging == "aar":
target_import_string = ["aar_import("]
else:
Expand Down Expand Up @@ -382,7 +389,7 @@ def _coursier_fetch_impl(repository_ctx):
cmd = _generate_coursier_command(repository_ctx)
cmd.extend(["fetch"])
cmd.extend(artifact_coordinates)
cmd.extend(["--artifact-type", ",".join(_COURSIER_PACKAGING_TYPES)])
cmd.extend(["--artifact-type", ",".join(_COURSIER_PACKAGING_TYPES + ["src"])])
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drive-by fix to add src back into the fetch_sources branch.

cmd.append("--quiet")
cmd.append("--no-default")
cmd.extend(["--json-output-file", "dep-tree.json"])
Expand Down Expand Up @@ -439,9 +446,19 @@ def _coursier_fetch_impl(repository_ctx):
srcs_dep_tree = srcs_dep_tree,
)

repository_ctx.template(
"jvm_import.bzl",
repository_ctx.attr._jvm_import,
substitutions = {},
executable = False, # not executable
)

repository_ctx.file(
"BUILD",
_BUILD.format(imports = generated_imports),
_BUILD.format(
repository_name = repository_ctx.name,
imports = generated_imports,
),
False, # not executable
)

Expand All @@ -457,7 +474,10 @@ def _coursier_fetch_impl(repository_ctx):

coursier_fetch = repository_rule(
attrs = {
"_coursier": attr.label(default = "//:third_party/coursier/coursier"), # vendor coursier, it's just a jar
"_coursier": attr.label(
default = "//:third_party/coursier/coursier",
), # vendor coursier, it's just a jar
"_jvm_import": attr.label(default = "//:private/jvm_import.bzl"),
"repositories": attr.string_list(), # list of repository objects, each as json
"artifacts": attr.string_list(), # list of artifact objects, each as json
"fetch_sources": attr.bool(default = False),
Expand Down
10 changes: 10 additions & 0 deletions examples/android_kotlin_app/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bazel"
android:versionCode="1"
android:versionName="1.0">

<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="26" />

</manifest>
8 changes: 8 additions & 0 deletions examples/android_kotlin_app/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
android_binary(
name = "app",
manifest = "AndroidManifest.xml",
custom_package = "com.example.bazel",
deps = [
"//src:lib",
],
)
37 changes: 37 additions & 0 deletions examples/android_kotlin_app/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

android_sdk_repository(name = "androidsdk")

# BEGIN io_bazel_rules_kotlin

RULES_KOTLIN_VERSION = "da1232eda2ef90d4375e2d1677b32c7ddf09e8a1"
http_archive(
name = "io_bazel_rules_kotlin",
strip_prefix = "rules_kotlin-%s" % RULES_KOTLIN_VERSION,
url = "https://github.com/bazelbuild/rules_kotlin/archive/%s.tar.gz" % RULES_KOTLIN_VERSION,
sha256 = "0bbb0e5e536f0c775f37bded59d4f8cfb8556e6c3d926fcc0f58bf3489bff470",
)
load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kotlin_repositories", "kt_register_toolchains")

kotlin_repositories()
kt_register_toolchains()

# END io_bazel_rules_kotlin

local_repository(
name = "rules_jvm_external",
path = "../../",
)

load("@rules_jvm_external//:defs.bzl", "maven_install")

maven_install(
artifacts = [
"androidx.appcompat:appcompat:1.0.2",
"androidx.core:core-ktx:1.0.1",
],
repositories = [
"https://maven.google.com",
"https://repo1.maven.org/maven2",
],
)
22 changes: 22 additions & 0 deletions examples/android_kotlin_app/src/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bazel"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="26" />

<application
android:label="rules_jvm_external Kotlin App">
<activity
android:name=".MainActivity"
android:theme="@style/AppTheme"
android:label="rules_jvm_external Kotlin App">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
20 changes: 20 additions & 0 deletions examples/android_kotlin_app/src/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_android_library")
load("@rules_jvm_external//:defs.bzl", "artifact")

kt_android_library(
name = "lib",
srcs = glob(["java/com/example/bazel/*.kt"]),
manifest = "AndroidManifest.xml",
custom_package = "com.example.bazel",
resource_files = glob(["res/**"]),
deps = [
"@maven//:androidx_appcompat_appcompat",
"@maven//:androidx_core_core",
"@maven//:androidx_core_core_ktx",
"@maven//:androidx_drawerlayout_drawerlayout",
"@maven//:androidx_fragment_fragment",
"@maven//:androidx_lifecycle_lifecycle_common",
"@maven//:androidx_lifecycle_lifecycle_viewmodel",
],
visibility = ["//:__pkg__"]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.bazel

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.setContentView(R.layout.activity_main)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame,UnusedIds" />
9 changes: 9 additions & 0 deletions examples/android_kotlin_app/src/res/values/styles.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!--&lt;!&ndash; Customize your theme here. &ndash;&gt;-->
</style>

</resources>
55 changes: 55 additions & 0 deletions private/jvm_import.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Stripped down version of a java_import Starlark rule, without invoking ijar
# to create interface jars.

# Inspired by Square's implementation of `raw_jvm_import` [0] and discussions
# on the GitHub thread [1] about ijar's interaction with Kotlin JARs.
#
# [0]: https://github.com/square/bazel_maven_repository/pull/48
# [1]: https://github.com/bazelbuild/bazel/issues/4549


def _jvm_import_impl(ctx):
if len(ctx.files.jars) != 1:
fail("Please only specify one jar to import in the jars attribute.")

return [
DefaultInfo(
files = depset(ctx.files.jars)
),
JavaInfo(
compile_jar = ctx.files.jars[0],
output_jar = ctx.files.jars[0],
source_jar = ctx.file.srcjar,
deps = [
dep[JavaInfo]
for dep
in ctx.attr.deps
if JavaInfo in dep
],
)
]


jvm_import = rule(
attrs={
"jars":
attr.label_list(
allow_files=True,
mandatory=True,
cfg="target",
),
"srcjar":
attr.label(
allow_single_file=True,
mandatory=False,
cfg="target",
),
"deps":
attr.label_list(
default=[],
providers=[JavaInfo],
),
},
implementation=_jvm_import_impl,
provides=[JavaInfo],
)
11 changes: 11 additions & 0 deletions tests/unit/kotlin/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_test")

kt_jvm_test(
name = "inline_function_test",
srcs = ["com/example/bazel/InlineFunctionTest.kt"],
test_class = "com.example.bazel.InlineFunctionTest",
deps = [
"@kotlin_tests//:junit_junit",
"@kotlin_tests//:org_jetbrains_kotlin_kotlin_test",
]
)
Loading