blob: f3c5fa19a6c1341fb0af81a6bef0a41e925eb48f [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001# Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
laurentlba7f3b852018-09-03 04:29:01 -070015"""Java rules for bootstraping Bazel.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010016
laurentlba7f3b852018-09-03 04:29:01 -070017
18This is a quick and dirty rule to make Bazel compile itself. It's not production
19ready.
20"""
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010021
cparsons3f87a952019-04-19 12:13:36 -070022_JarsInfo = provider(fields = ["compile_time_jars", "runtime_jars"])
23
24def _java_library_impl(ctx):
vladmos20a042f2018-06-01 04:51:21 -070025 javac_options = ctx.fragments.java.default_javac_flags
26 class_jar = ctx.outputs.class_jar
27 compile_time_jars = depset(order = "topological")
28 runtime_jars = depset(order = "topological")
29 for dep in ctx.attr.deps:
cparsons3f87a952019-04-19 12:13:36 -070030 compile_time_jars = depset(
31 transitive = [compile_time_jars, dep[_JarsInfo].compile_time_jars],
32 )
33 runtime_jars = depset(
34 transitive = [runtime_jars, dep[_JarsInfo].runtime_jars],
35 )
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010036
laurentlba7f3b852018-09-03 04:29:01 -070037 jars = ctx.files.jars
38 neverlink_jars = ctx.files.neverlink_jars
laurentlbe5d42192019-04-25 10:50:14 -070039 compile_time_jars = depset(jars + neverlink_jars, transitive = [compile_time_jars])
40 runtime_jars = depset(jars, transitive = [runtime_jars])
twerthb57c2a42018-11-13 11:23:59 -080041 compile_time_jars_list = compile_time_jars.to_list() # TODO: This is weird.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010042
vladmos20a042f2018-06-01 04:51:21 -070043 build_output = class_jar.path + ".build_output"
44 java_output = class_jar.path + ".build_java"
45 javalist_output = class_jar.path + ".build_java_list"
46 sources = ctx.files.srcs
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010047
laurentlbf09429c2018-11-14 06:07:43 -080048 sources_param_file = ctx.actions.declare_file(class_jar.basename + "-2.params")
49 ctx.actions.write(
vladmos20a042f2018-06-01 04:51:21 -070050 output = sources_param_file,
51 content = cmd_helper.join_paths("\n", depset(sources)),
laurentlbf09429c2018-11-14 06:07:43 -080052 is_executable = False,
vladmos20a042f2018-06-01 04:51:21 -070053 )
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010054
vladmos20a042f2018-06-01 04:51:21 -070055 # Cleaning build output directory
56 cmd = "set -e;rm -rf " + build_output + " " + java_output + " " + javalist_output + "\n"
57 cmd += "mkdir " + build_output + " " + java_output + "\n"
58 files = " @" + sources_param_file.path
cushon366da4c2018-08-08 08:38:54 -070059 java_runtime = ctx.attr._jdk[java_common.JavaRuntimeInfo]
60 jar_path = "%s/bin/jar" % java_runtime.java_home
Damien Martin-Guillerezd6f48082015-06-05 10:50:43 +000061
vladmos20a042f2018-06-01 04:51:21 -070062 if ctx.files.srcjars:
63 files += " @" + javalist_output
64 for file in ctx.files.srcjars:
cushon366da4c2018-08-08 08:38:54 -070065 cmd += "%s tf %s | grep '\.java$' | sed 's|^|%s/|' >> %s\n" % (jar_path, file.path, java_output, javalist_output)
vladmos20a042f2018-06-01 04:51:21 -070066 cmd += "unzip %s -d %s >/dev/null\n" % (file.path, java_output)
Damien Martin-Guillerezd6f48082015-06-05 10:50:43 +000067
vladmos20a042f2018-06-01 04:51:21 -070068 if ctx.files.srcs or ctx.files.srcjars:
cushon366da4c2018-08-08 08:38:54 -070069 cmd += "%s/bin/javac" % java_runtime.java_home
vladmos20a042f2018-06-01 04:51:21 -070070 cmd += " " + " ".join(javac_options)
71 if compile_time_jars:
72 cmd += " -classpath '" + cmd_helper.join_paths(ctx.configuration.host_path_separator, compile_time_jars) + "'"
73 cmd += " -d " + build_output + files + "\n"
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074
vladmos20a042f2018-06-01 04:51:21 -070075 # We haven't got a good story for where these should end up, so
76 # stick them in the root of the jar.
77 for r in ctx.files.resources:
78 cmd += "cp %s %s\n" % (r.path, build_output)
cushon366da4c2018-08-08 08:38:54 -070079 cmd += (jar_path + " cf " + class_jar.path + " -C " + build_output + " .\n" +
vladmos20a042f2018-06-01 04:51:21 -070080 "touch " + build_output + "\n")
laurentlbf09429c2018-11-14 06:07:43 -080081 ctx.actions.run_shell(
vladmos20a042f2018-06-01 04:51:21 -070082 inputs = (sources + compile_time_jars_list + [sources_param_file] +
cushon366da4c2018-08-08 08:38:54 -070083 ctx.files._jdk + ctx.files.resources + ctx.files.srcjars),
vladmos20a042f2018-06-01 04:51:21 -070084 outputs = [class_jar],
85 mnemonic = "JavacBootstrap",
86 command = cmd,
87 use_default_shell_env = True,
88 )
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010089
vladmos20a042f2018-06-01 04:51:21 -070090 runfiles = ctx.runfiles(collect_data = True)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010091
cparsons3f87a952019-04-19 12:13:36 -070092 compile_time_jars = depset(transitive = [compile_time_jars], direct = [class_jar])
93 runtime_jars = depset(transitive = [runtime_jars], direct = [class_jar])
94
95 return [
96 DefaultInfo(
cparsons6e821a12019-04-04 12:46:55 -070097 files = depset([class_jar]),
98 runfiles = runfiles,
cparsons3f87a952019-04-19 12:13:36 -070099 ),
100 _JarsInfo(
101 compile_time_jars = compile_time_jars,
102 runtime_jars = runtime_jars,
103 ),
104 ]
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100105
cparsons3f87a952019-04-19 12:13:36 -0700106def _java_binary_impl(ctx):
107 library_result = _java_library_impl(ctx)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100108
vladmos20a042f2018-06-01 04:51:21 -0700109 deploy_jar = ctx.outputs.deploy_jar
110 manifest = ctx.outputs.manifest
111 build_output = deploy_jar.path + ".build_output"
112 main_class = ctx.attr.main_class
cushon366da4c2018-08-08 08:38:54 -0700113 java_runtime = ctx.attr._jdk[java_common.JavaRuntimeInfo]
114 jar_path = "%s/bin/jar" % java_runtime.java_home
laurentlbf09429c2018-11-14 06:07:43 -0800115 ctx.actions.write(
vladmos20a042f2018-06-01 04:51:21 -0700116 output = manifest,
117 content = "Main-Class: " + main_class + "\n",
laurentlbf09429c2018-11-14 06:07:43 -0800118 is_executable = False,
vladmos20a042f2018-06-01 04:51:21 -0700119 )
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100120
vladmos20a042f2018-06-01 04:51:21 -0700121 # Cleaning build output directory
122 cmd = "set -e;rm -rf " + build_output + ";mkdir " + build_output + "\n"
laurentlb67ba1d62019-06-03 07:58:51 -0700123 for jar in library_result[1].runtime_jars.to_list():
vladmos20a042f2018-06-01 04:51:21 -0700124 cmd += "unzip -qn " + jar.path + " -d " + build_output + "\n"
cushon366da4c2018-08-08 08:38:54 -0700125 cmd += (jar_path + " cmf " + manifest.path + " " +
vladmos20a042f2018-06-01 04:51:21 -0700126 deploy_jar.path + " -C " + build_output + " .\n" +
127 "touch " + build_output + "\n")
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100128
laurentlbf09429c2018-11-14 06:07:43 -0800129 ctx.actions.run_shell(
laurentlb67ba1d62019-06-03 07:58:51 -0700130 inputs = library_result[1].runtime_jars.to_list() + [manifest] + ctx.files._jdk,
vladmos20a042f2018-06-01 04:51:21 -0700131 outputs = [deploy_jar],
132 mnemonic = "Deployjar",
133 command = cmd,
134 use_default_shell_env = True,
135 )
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100136
vladmos20a042f2018-06-01 04:51:21 -0700137 # Write the wrapper.
138 executable = ctx.outputs.executable
laurentlbf09429c2018-11-14 06:07:43 -0800139 ctx.actions.write(
vladmos20a042f2018-06-01 04:51:21 -0700140 output = executable,
141 content = "\n".join([
142 "#!/bin/bash",
143 "# autogenerated - do not edit.",
144 "case \"$0\" in",
145 "/*) self=\"$0\" ;;",
146 "*) self=\"$PWD/$0\";;",
147 "esac",
148 "",
149 "if [[ -z \"$JAVA_RUNFILES\" ]]; then",
150 " if [[ -e \"${self}.runfiles\" ]]; then",
151 " export JAVA_RUNFILES=\"${self}.runfiles\"",
152 " fi",
153 " if [[ -n \"$JAVA_RUNFILES\" ]]; then",
154 " export TEST_SRCDIR=${TEST_SRCDIR:-$JAVA_RUNFILES}",
155 " fi",
156 "fi",
157 "",
cushon366da4c2018-08-08 08:38:54 -0700158 "jvm_bin=%s" % (ctx.attr._jdk[java_common.JavaRuntimeInfo].java_executable_exec_path),
vladmos20a042f2018-06-01 04:51:21 -0700159 "if [[ ! -x ${jvm_bin} ]]; then",
160 " jvm_bin=$(which java)",
161 "fi",
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100162
vladmos20a042f2018-06-01 04:51:21 -0700163 # We extract the .so into a temp dir. If only we could mmap
164 # directly from the zip file.
165 "DEPLOY=$(dirname $self)/$(basename %s)" % deploy_jar.path,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100166
vladmos20a042f2018-06-01 04:51:21 -0700167 # This works both on Darwin and Linux, with the darwin path
168 # looking like tmp.XXXXXXXX.{random}
169 "SO_DIR=$(mktemp -d -t tmp.XXXXXXXXX)",
170 "function cleanup() {",
171 " rm -rf ${SO_DIR}",
172 "}",
173 "trap cleanup EXIT",
174 "unzip -q -d ${SO_DIR} ${DEPLOY} \"*.so\" \"*.dll\" \"*.dylib\" >& /dev/null",
175 ("${jvm_bin} -Djava.library.path=${SO_DIR} %s -jar $DEPLOY \"$@\"" %
176 " ".join(ctx.attr.jvm_flags)),
177 "",
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100178 ]),
laurentlbf09429c2018-11-14 06:07:43 -0800179 is_executable = True,
vladmos20a042f2018-06-01 04:51:21 -0700180 )
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100181
vladmos20a042f2018-06-01 04:51:21 -0700182 runfiles = ctx.runfiles(files = [deploy_jar, executable] + ctx.files._jdk, collect_data = True)
cparsons3f87a952019-04-19 12:13:36 -0700183 files_to_build = depset(
184 transitive = [library_result[0].files],
185 direct = [deploy_jar, manifest, executable],
186 )
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100187
cparsons6e821a12019-04-04 12:46:55 -0700188 return [DefaultInfo(files = files_to_build, runfiles = runfiles)]
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100189
cparsons3f87a952019-04-19 12:13:36 -0700190def _java_import_impl(ctx):
vladmos20a042f2018-06-01 04:51:21 -0700191 # TODO(bazel-team): Why do we need to filter here? The attribute
192 # already says only jars are allowed.
laurentlba7f3b852018-09-03 04:29:01 -0700193 jars = depset(ctx.files.jars)
194 neverlink_jars = depset(ctx.files.neverlink_jars)
vladmos20a042f2018-06-01 04:51:21 -0700195 runfiles = ctx.runfiles(collect_data = True)
cparsons3f87a952019-04-19 12:13:36 -0700196 compile_time_jars = depset(transitive = [jars, neverlink_jars])
197
198 return [
199 DefaultInfo(files = jars, runfiles = runfiles),
200 _JarsInfo(
201 compile_time_jars = compile_time_jars,
202 runtime_jars = jars,
203 ),
204 ]
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100205
206java_library_attrs = {
cushon366da4c2018-08-08 08:38:54 -0700207 "_jdk": attr.label(
208 default = Label("//tools/jdk:current_java_runtime"),
209 providers = [java_common.JavaRuntimeInfo],
210 ),
gregced92725b2018-07-09 15:30:19 -0700211 "data": attr.label_list(allow_files = True),
vladmos20a042f2018-06-01 04:51:21 -0700212 "resources": attr.label_list(allow_files = True),
laurentlba7f3b852018-09-03 04:29:01 -0700213 "srcs": attr.label_list(allow_files = [".java"]),
214 "jars": attr.label_list(allow_files = [".jar"]),
215 "neverlink_jars": attr.label_list(allow_files = [".jar"]),
216 "srcjars": attr.label_list(allow_files = [".jar", ".srcjar"]),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100217 "deps": attr.label_list(
vladmos20a042f2018-06-01 04:51:21 -0700218 allow_files = False,
cparsons3f87a952019-04-19 12:13:36 -0700219 providers = [_JarsInfo],
vladmos20a042f2018-06-01 04:51:21 -0700220 ),
221}
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100222
223java_library = rule(
cparsons3f87a952019-04-19 12:13:36 -0700224 _java_library_impl,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100225 attrs = java_library_attrs,
226 outputs = {
227 "class_jar": "lib%{name}.jar",
Ulf Adams52bcf5a2015-08-24 07:41:45 +0000228 },
vladmos20a042f2018-06-01 04:51:21 -0700229 fragments = ["java", "cpp"],
Ulf Adams52bcf5a2015-08-24 07:41:45 +0000230)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100231
Damien Martin-Guillerezd6f48082015-06-05 10:50:43 +0000232# A copy to avoid conflict with native rule.
233bootstrap_java_library = rule(
cparsons3f87a952019-04-19 12:13:36 -0700234 _java_library_impl,
Damien Martin-Guillerezd6f48082015-06-05 10:50:43 +0000235 attrs = java_library_attrs,
236 outputs = {
237 "class_jar": "lib%{name}.jar",
Ulf Adams52bcf5a2015-08-24 07:41:45 +0000238 },
vladmos20a042f2018-06-01 04:51:21 -0700239 fragments = ["java"],
Ulf Adams52bcf5a2015-08-24 07:41:45 +0000240)
Damien Martin-Guillerezd6f48082015-06-05 10:50:43 +0000241
vladmosceaed512018-01-03 12:20:57 -0800242java_binary_attrs_common = dict(java_library_attrs)
243java_binary_attrs_common.update({
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100244 "jvm_flags": attr.string_list(),
vladmos20a042f2018-06-01 04:51:21 -0700245 "jvm": attr.label(default = Label("//tools/jdk:jdk"), allow_files = True),
vladmosceaed512018-01-03 12:20:57 -0800246})
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100247
vladmosceaed512018-01-03 12:20:57 -0800248java_binary_attrs = dict(java_binary_attrs_common)
vladmos20a042f2018-06-01 04:51:21 -0700249java_binary_attrs["main_class"] = attr.string(mandatory = True)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100250
251java_binary_outputs = {
252 "class_jar": "lib%{name}.jar",
253 "deploy_jar": "%{name}_deploy.jar",
vladmos20a042f2018-06-01 04:51:21 -0700254 "manifest": "%{name}_MANIFEST.MF",
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100255}
256
vladmos20a042f2018-06-01 04:51:21 -0700257java_binary = rule(
cparsons3f87a952019-04-19 12:13:36 -0700258 _java_binary_impl,
vladmos20a042f2018-06-01 04:51:21 -0700259 executable = True,
260 attrs = java_binary_attrs,
261 outputs = java_binary_outputs,
262 fragments = ["java", "cpp"],
Ulf Adams52bcf5a2015-08-24 07:41:45 +0000263)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100264
Damien Martin-Guillerezd6f48082015-06-05 10:50:43 +0000265# A copy to avoid conflict with native rule
vladmos20a042f2018-06-01 04:51:21 -0700266bootstrap_java_binary = rule(
cparsons3f87a952019-04-19 12:13:36 -0700267 _java_binary_impl,
vladmos20a042f2018-06-01 04:51:21 -0700268 executable = True,
269 attrs = java_binary_attrs,
270 outputs = java_binary_outputs,
271 fragments = ["java"],
Ulf Adams52bcf5a2015-08-24 07:41:45 +0000272)
Damien Martin-Guillerezd6f48082015-06-05 10:50:43 +0000273
vladmos20a042f2018-06-01 04:51:21 -0700274java_test = rule(
cparsons3f87a952019-04-19 12:13:36 -0700275 _java_binary_impl,
vladmos20a042f2018-06-01 04:51:21 -0700276 executable = True,
Googler9a8318e2019-01-11 11:12:01 -0800277 attrs = dict(list(java_binary_attrs_common.items()) + [
vladmos20a042f2018-06-01 04:51:21 -0700278 ("main_class", attr.string(default = "org.junit.runner.JUnitCore")),
279 # TODO(bazel-team): it would be better if we could offer a
280 # test_class attribute, but the "args" attribute is hard
281 # coded in the bazel infrastructure.
282 ]),
283 outputs = java_binary_outputs,
284 test = True,
285 fragments = ["java", "cpp"],
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100286)
287
288java_import = rule(
cparsons3f87a952019-04-19 12:13:36 -0700289 _java_import_impl,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100290 attrs = {
laurentlba7f3b852018-09-03 04:29:01 -0700291 "jars": attr.label_list(allow_files = [".jar"]),
292 "srcjar": attr.label(allow_files = [".jar", ".srcjar"]),
293 "neverlink_jars": attr.label_list(allow_files = [".jar"], default = []),
vladmos20a042f2018-06-01 04:51:21 -0700294 },
295)