Skip to content

Commit

Permalink
Add Scala library rule.
Browse files Browse the repository at this point in the history
--
MOS_MIGRATED_REVID=102038201
  • Loading branch information
laurentlb authored and jhfield committed Sep 2, 2015
1 parent 410405e commit 868d40c
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 0 deletions.
17 changes: 17 additions & 0 deletions tools/build_defs/scala/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Scala Rules for Bazel

## Overview

This rule is used for building [Scala][scala] projects with Bazel. There is
currently only one rule, `scala_library`. More features will be added in the
future, e.g. `scala_binary`, `scala_test`, etc.

[scala]: http://www.scala-lang.org/

### `scala_library`

`scala_library` generates a `.jar` file from `.scala` source files. In order to
make a java rule use this jar file, use the `java_import` rule.

The current implementation assumes that the files `/usr/bin/scalac` and
`/usr/share/java/scala-library.jar` exist.
97 changes: 97 additions & 0 deletions tools/build_defs/scala/scala.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Copyright 2015 Google Inc. 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.

"""Rules for supporting the Scala language."""


_scala_filetype = FileType([".scala"])

# TODO(bazel-team): Add local_repository to properly declare the dependency.
_scala_library_path = "/usr/share/java/scala-library.jar"
_scalac_path = "/usr/bin/scalac"

def _compile(ctx, jars):
cmd = """
mkdir -p {out}_tmp
{scalac} -classpath "{jars}" $@ -d {out}_tmp &&
# Make jar file deterministic by setting the timestamp of files
touch -t 198001010000 $(find .)
jar cmf {manifest} {out} -C {out}_tmp .
"""
cmd = cmd.format(
scalac=_scalac_path,
out=ctx.outputs.jar.path,
manifest=ctx.outputs.manifest.path,
jars=':'.join([j.path for j in jars]))

ctx.action(
inputs=list(jars) + ctx.files.srcs + [ctx.outputs.manifest],
outputs=[ctx.outputs.jar],
command=cmd,
progress_message="scala %s" % ctx.label,
arguments=[f.path for f in ctx.files.srcs])


def _write_manifest(ctx):
manifest = """Main-Class: {main_class}
Class-Path: {cp}
"""
manifest = manifest.format(
main_class=ctx.attr.main_class,
cp=_scala_library_path)

ctx.file_action(
output = ctx.outputs.manifest,
content = manifest)


def _collect_jars(ctx):
jars = set()
for target in ctx.attr.deps:
if hasattr(target, "jar_files"):
jars += target.jar_files
elif hasattr(target, "java"):
jars += target.java.transitive_runtime_deps
return jars


def _scala_library_impl(ctx):
jars = _collect_jars(ctx)
_write_manifest(ctx)
_compile(ctx, jars)

all_jars = jars + [ctx.outputs.jar]

runfiles = ctx.runfiles(
files = list(all_jars) + [ctx.outputs.jar],
collect_data = True)
return struct(
files=all_jars,
jar_files=all_jars,
runfiles=runfiles)


scala_library = rule(
implementation=_scala_library_impl,
attrs={
"main_class": attr.string(mandatory=True),
"srcs": attr.label_list(allow_files=_scala_filetype),
"deps": attr.label_list(),
"data": attr.label_list(allow_files=True, cfg=DATA_CFG),
},
outputs={
"jar": "%{name}_deploy.jar",
"manifest": "%{name}_MANIFEST.MF",
},
)
28 changes: 28 additions & 0 deletions tools/build_defs/scala/test/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
load("/tools/build_defs/scala/scala", "scala_library")

java_binary(
name = "Hello",
srcs = ["Hello.java"],
main_class = "scala.test.Hello",
deps = [":lib_import"],
)

# TODO(bazel-team): Allow java rules to depend directly on scala_library.
# For now, we have to use a java_import proxy.
java_import(
name = "lib_import",
jars = [":HelloLib"],
)

scala_library(
name = "HelloLib",
srcs = ["HelloLib.scala"],
main_class = "scala.test.HelloLib",
deps = ["OtherLib"],
)

scala_library(
name = "OtherLib",
srcs = ["OtherLib.scala"],
main_class = "scala.test.OtherLib",
)
22 changes: 22 additions & 0 deletions tools/build_defs/scala/test/Hello.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2015 Google Inc. 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 scala.test;

/** Example class */
public class Hello {
public static void main(String[] args) {
HelloLib.printMessage("Hello");
}
}
7 changes: 7 additions & 0 deletions tools/build_defs/scala/test/HelloLib.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package scala.test

object HelloLib {
def printMessage(arg: String) {
println(arg + " " + OtherLib.getMessage())
}
}
8 changes: 8 additions & 0 deletions tools/build_defs/scala/test/OtherLib.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package scala.test

// It is just to show how a Scala library can depend on another Scala library.
object OtherLib {
def getMessage(): String = {
return "scala!"
}
}

0 comments on commit 868d40c

Please sign in to comment.