| # Copyright 2014 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. |
| |
| java_filetype = FileType([".java"]) |
| jar_filetype = FileType([".jar"]) |
| srcjar_filetype = FileType([".jar", ".srcjar"]) |
| |
| # This is a quick and dirty rule to make Bazel compile itself. It's not |
| # production ready. |
| |
| def java_library_impl(ctx): |
| javac_options = ctx.fragments.java.default_javac_flags |
| class_jar = ctx.outputs.class_jar |
| compile_time_jars = depset(order="topological") |
| runtime_jars = depset(order="topological") |
| for dep in ctx.attr.deps: |
| compile_time_jars += dep.compile_time_jars |
| runtime_jars += dep.runtime_jars |
| |
| jars = jar_filetype.filter(ctx.files.jars) |
| neverlink_jars = jar_filetype.filter(ctx.files.neverlink_jars) |
| compile_time_jars += jars + neverlink_jars |
| runtime_jars += jars |
| compile_time_jars_list = list(compile_time_jars) # TODO: This is weird. |
| |
| build_output = class_jar.path + ".build_output" |
| java_output = class_jar.path + ".build_java" |
| javalist_output = class_jar.path + ".build_java_list" |
| sources = ctx.files.srcs |
| |
| sources_param_file = ctx.new_file(ctx.bin_dir, class_jar, "-2.params") |
| ctx.file_action( |
| output = sources_param_file, |
| content = cmd_helper.join_paths("\n", depset(sources)), |
| executable = False) |
| |
| # Cleaning build output directory |
| cmd = "set -e;rm -rf " + build_output + " " + java_output + " " + javalist_output + "\n" |
| cmd += "mkdir " + build_output + " " + java_output + "\n" |
| files = " @" + sources_param_file.path |
| |
| if ctx.files.srcjars: |
| files += " @" + javalist_output |
| for file in ctx.files.srcjars: |
| cmd += "%s tf %s | grep '\.java$' | sed 's|^|%s/|' >> %s\n" % (ctx.file._jar.path, file.path, java_output, javalist_output) |
| cmd += "unzip %s -d %s >/dev/null\n" % (file.path, java_output) |
| |
| if ctx.files.srcs or ctx.files.srcjars: |
| cmd += ctx.file._javac.path |
| cmd += " " + " ".join(javac_options) |
| if compile_time_jars: |
| cmd += " -classpath '" + cmd_helper.join_paths(ctx.configuration.host_path_separator, compile_time_jars) + "'" |
| cmd += " -d " + build_output + files + "\n" |
| |
| # We haven't got a good story for where these should end up, so |
| # stick them in the root of the jar. |
| for r in ctx.files.resources: |
| cmd += "cp %s %s\n" % (r.path, build_output) |
| cmd += (ctx.file._jar.path + " cf " + class_jar.path + " -C " + build_output + " .\n" + |
| "touch " + build_output + "\n") |
| ctx.action( |
| inputs = (sources + compile_time_jars_list + [sources_param_file] + |
| [ctx.file._jar] + ctx.files._jdk + ctx.files.resources + ctx.files.srcjars), |
| outputs = [class_jar], |
| mnemonic='JavacBootstrap', |
| command=cmd, |
| use_default_shell_env=True) |
| |
| runfiles = ctx.runfiles(collect_data = True) |
| |
| return struct(files = depset([class_jar]), |
| compile_time_jars = compile_time_jars + [class_jar], |
| runtime_jars = runtime_jars + [class_jar], |
| runfiles = runfiles) |
| |
| |
| def java_binary_impl(ctx): |
| library_result = java_library_impl(ctx) |
| |
| deploy_jar = ctx.outputs.deploy_jar |
| manifest = ctx.outputs.manifest |
| build_output = deploy_jar.path + ".build_output" |
| main_class = ctx.attr.main_class |
| ctx.file_action( |
| output = manifest, |
| content = "Main-Class: " + main_class + "\n", |
| executable = False) |
| |
| # Cleaning build output directory |
| cmd = "set -e;rm -rf " + build_output + ";mkdir " + build_output + "\n" |
| for jar in library_result.runtime_jars: |
| cmd += "unzip -qn " + jar.path + " -d " + build_output + "\n" |
| cmd += (ctx.file._jar.path + " cmf " + manifest.path + " " + |
| deploy_jar.path + " -C " + build_output + " .\n" + |
| "touch " + build_output + "\n") |
| |
| ctx.action( |
| inputs=list(library_result.runtime_jars) + [manifest] + ctx.files._jdk, |
| outputs=[deploy_jar], |
| mnemonic='Deployjar', |
| command=cmd, |
| use_default_shell_env=True) |
| |
| # Write the wrapper. |
| executable = ctx.outputs.executable |
| ctx.file_action( |
| output = executable, |
| content = '\n'.join([ |
| "#!/bin/bash", |
| "# autogenerated - do not edit.", |
| "case \"$0\" in", |
| "/*) self=\"$0\" ;;", |
| "*) self=\"$PWD/$0\";;", |
| "esac", |
| "", |
| "if [[ -z \"$JAVA_RUNFILES\" ]]; then", |
| " if [[ -e \"${self}.runfiles\" ]]; then", |
| " export JAVA_RUNFILES=\"${self}.runfiles\"", |
| " fi", |
| " if [[ -n \"$JAVA_RUNFILES\" ]]; then", |
| " export TEST_SRCDIR=${TEST_SRCDIR:-$JAVA_RUNFILES}", |
| " fi", |
| "fi", |
| "", |
| |
| "jvm_bin=%s" % (ctx.file._java.path), |
| "if [[ ! -x ${jvm_bin} ]]; then", |
| " jvm_bin=$(which java)", |
| "fi", |
| |
| # We extract the .so into a temp dir. If only we could mmap |
| # directly from the zip file. |
| "DEPLOY=$(dirname $self)/$(basename %s)" % deploy_jar.path, |
| |
| # This works both on Darwin and Linux, with the darwin path |
| # looking like tmp.XXXXXXXX.{random} |
| "SO_DIR=$(mktemp -d -t tmp.XXXXXXXXX)", |
| "function cleanup() {", |
| " rm -rf ${SO_DIR}", |
| "}", |
| "trap cleanup EXIT", |
| "unzip -q -d ${SO_DIR} ${DEPLOY} \"*.so\" \"*.dll\" \"*.dylib\" >& /dev/null", |
| ("${jvm_bin} -Djava.library.path=${SO_DIR} %s -jar $DEPLOY \"$@\"" |
| % ' '.join(ctx.attr.jvm_flags)) , |
| "", |
| ]), |
| executable = True) |
| |
| runfiles = ctx.runfiles(files = [deploy_jar, executable] + ctx.files._jdk, collect_data = True) |
| files_to_build = depset([deploy_jar, manifest, executable]) |
| files_to_build += library_result.files |
| |
| return struct(files = files_to_build, runfiles = runfiles) |
| |
| |
| def java_import_impl(ctx): |
| # TODO(bazel-team): Why do we need to filter here? The attribute |
| # already says only jars are allowed. |
| jars = depset(jar_filetype.filter(ctx.files.jars)) |
| neverlink_jars = depset(jar_filetype.filter(ctx.files.neverlink_jars)) |
| runfiles = ctx.runfiles(collect_data = True) |
| return struct(files = jars, |
| compile_time_jars = jars + neverlink_jars, |
| runtime_jars = jars, |
| runfiles = runfiles) |
| |
| |
| java_library_attrs = { |
| "_java": attr.label(default=Label("//tools/jdk:java"), single_file=True), |
| "_javac": attr.label(default=Label("//tools/jdk:javac"), single_file=True), |
| "_jar": attr.label(default=Label("//tools/jdk:jar"), single_file=True), |
| "_jdk": attr.label(default=Label("//tools/jdk:jdk"), allow_files=True), |
| "data": attr.label_list(allow_files=True, cfg="data"), |
| "resources": attr.label_list(allow_files=True), |
| "srcs": attr.label_list(allow_files=java_filetype), |
| "jars": attr.label_list(allow_files=jar_filetype), |
| "neverlink_jars": attr.label_list(allow_files=jar_filetype), |
| "srcjars": attr.label_list(allow_files=srcjar_filetype), |
| "deps": attr.label_list( |
| allow_files=False, |
| providers = ["compile_time_jars", "runtime_jars"]), |
| } |
| |
| java_library = rule( |
| java_library_impl, |
| attrs = java_library_attrs, |
| outputs = { |
| "class_jar": "lib%{name}.jar", |
| }, |
| fragments = ['java', 'cpp'], |
| ) |
| |
| # A copy to avoid conflict with native rule. |
| bootstrap_java_library = rule( |
| java_library_impl, |
| attrs = java_library_attrs, |
| outputs = { |
| "class_jar": "lib%{name}.jar", |
| }, |
| fragments = ['java'], |
| ) |
| |
| java_binary_attrs_common = dict(java_library_attrs) |
| java_binary_attrs_common.update({ |
| "jvm_flags": attr.string_list(), |
| "jvm": attr.label(default=Label("//tools/jdk:jdk"), allow_files=True), |
| }) |
| |
| java_binary_attrs = dict(java_binary_attrs_common) |
| java_binary_attrs["main_class"] = attr.string(mandatory=True) |
| |
| java_binary_outputs = { |
| "class_jar": "lib%{name}.jar", |
| "deploy_jar": "%{name}_deploy.jar", |
| "manifest": "%{name}_MANIFEST.MF" |
| } |
| |
| java_binary = rule(java_binary_impl, |
| executable = True, |
| attrs = java_binary_attrs, |
| outputs = java_binary_outputs, |
| fragments = ['java', 'cpp'], |
| ) |
| |
| # A copy to avoid conflict with native rule |
| bootstrap_java_binary = rule(java_binary_impl, |
| executable = True, |
| attrs = java_binary_attrs, |
| outputs = java_binary_outputs, |
| fragments = ['java'], |
| ) |
| |
| java_test = rule(java_binary_impl, |
| executable = True, |
| attrs = dict(java_binary_attrs_common.items() + [ |
| ("main_class", attr.string(default="org.junit.runner.JUnitCore")), |
| # TODO(bazel-team): it would be better if we could offer a |
| # test_class attribute, but the "args" attribute is hard |
| # coded in the bazel infrastructure. |
| ]), |
| outputs = java_binary_outputs, |
| test = True, |
| fragments = ['java', 'cpp'], |
| ) |
| |
| java_import = rule( |
| java_import_impl, |
| attrs = { |
| "jars": attr.label_list(allow_files=jar_filetype), |
| "srcjar": attr.label(allow_files=srcjar_filetype), |
| "neverlink_jars": attr.label_list(allow_files=jar_filetype, default=[]), |
| }) |