Skip to content

Commit

Permalink
Build a version of Bazel with a bundled OpenJDK inside the binary.
Browse files Browse the repository at this point in the history
We're using Azul Systems, Inc.'s Zulu® OpenJDK build[1], as it's a good
vanilla build of OpenJDK available for our three most important
platforms:

  zulu8.20.0.5-jdk8.0.121-linux_x64.tar.gz
  zulu8.20.0.5-jdk8.0.121-macosx_x64.zip
  zulu8.20.0.5-jdk8.0.121-win_x64.zip

You can build & run a Bazel binary with an embedded JDK by simple doing:

  bazel build //src:bazel_with_jdk
  bazel-bin/src/bazel_with_jdk info

The "bazel license" command prints the license of the embedded OpenJDK.

We mirror the binaries and sources of the OpenJDK used for bundling on
this website:

https://bazel-mirror.storage.googleapis.com/openjdk/index.html

RELNOTES: Bazel can now be built with a bundled version of the OpenJDK.
This makes it possible to use Bazel on systems without a JDK, or where
the installed JDK is too old.

[1] http://www.azul.com/downloads/zulu/

--
PiperOrigin-RevId: 150440467
MOS_MIGRATED_REVID=150440467
  • Loading branch information
philwo authored and hermione521 committed Mar 20, 2017
1 parent 6b2d8b8 commit 9504827
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 7 deletions.
19 changes: 19 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,22 @@ new_local_repository(
path = "./third_party/protobuf/3.0.0/",
build_file = "./third_party/protobuf/3.0.0/com_google_protobuf_java.BUILD",
)

# OpenJDK distributions used to create a version of Bazel bundled with the OpenJDK.
http_file(
name = "openjdk_linux",
url = "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.20.0.5-jdk8.0.121/zulu8.20.0.5-jdk8.0.121-linux_x64.tar.gz",
sha256 = "7fdfb17d890406470b2303d749d3138e7f353749e67a0a22f542e1ab3e482745",
)

http_file(
name = "openjdk_macos",
url = "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.20.0.5-jdk8.0.121/zulu8.20.0.5-jdk8.0.121-macosx_x64.zip",
sha256 = "2a58bd1d9b0cbf0b3d8d1bcdd117c407e3d5a0ec01e2f53565c9bec5cf9ea78b",
)

http_file(
name = "openjdk_win",
url = "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.20.0.5-jdk8.0.121/zulu8.20.0.5-jdk8.0.121-win_x64.zip",
sha256 = "35414df28f17704546b9559b5e62b4d00cdc8fdfd349116be4f987abaeaaff68",
)
7 changes: 7 additions & 0 deletions scripts/ci/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ _Notice_: Bazel installers contain binaries licensed under the GPLv2 with
Classpath exception. Those installers should always be redistributed along with
the source code.
Some versions of Bazel contain a bundled version of OpenJDK. The license of the
bundled OpenJDK and other open-source components can be displayed by running
the command `bazel license`. The vendor and version information of the bundled
OpenJDK can be displayed by running the command `bazel info java-runtime`.
The binaries and source-code of the bundled OpenJDK can be
[downloaded from our mirror server](https://bazel-mirror.storage.googleapis.com/openjdk/index.html).
_Security_: All our binaries are signed with our
[public key](https://bazel.build/bazel-release.pub.gpg) 48457EE0.
"
Expand Down
35 changes: 29 additions & 6 deletions src/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ filegroup(
}),
) for suffix, embedded_tools in {
"": [":embedded_tools"],
"_with_jdk": [":embedded_tools_with_jdk"],
"_notools": [],
}.items()]

Expand Down Expand Up @@ -127,8 +128,8 @@ filegroup(
],
)

genrule(
name = "embedded_tools",
[genrule(
name = "embedded_tools" + suffix,
srcs = [
":create_embedded_tools.sh",
"//tools:embedded_tools_srcs",
Expand Down Expand Up @@ -171,14 +172,33 @@ genrule(
"//conditions:default": [
"//src/java_tools/buildjar/java/com/google/devtools/build/java/turbine:turbine_deploy.jar",
],
}),
outs = ["embedded_tools.zip"],
}) + (select({
":darwin": [
"@openjdk_macos//file",
],
":darwin_x86_64": [
"@openjdk_macos//file",
],
":windows": [
"@openjdk_win//file",
],
":windows_msvc": [
"@openjdk_win//file",
],
"//conditions:default": [
"@openjdk_linux//file",
],
}) if (suffix == "_with_jdk") else []),
outs = ["embedded_tools" + suffix + ".zip"],
cmd = "$(location :create_embedded_tools.sh) $@ $(SRCS)",
)
) for suffix in [
"",
"_with_jdk",
]]

[genrule(
name = "package-zip" + suffix,
srcs = ([":embedded_tools.zip"] if embed else []) + [
srcs = ([":embedded_tools" + suffix + ".zip"] if embed else []) + [
# The script assumes that the embedded tools zip (if exists) is the
# first item here, the deploy jar the second and install base key is the
# third
Expand All @@ -199,6 +219,7 @@ genrule(
) for suffix, embed in [
("", True),
("_notools", False),
("_with_jdk", True),
]]

[genrule(
Expand All @@ -223,6 +244,7 @@ genrule(
) for suffix in [
"",
"_notools",
"_with_jdk",
]]

# Build an executable named `bazel.exe`.
Expand All @@ -243,6 +265,7 @@ genrule(
) for suffix in [
"",
"_notools",
"_with_jdk",
]]

config_setting(
Expand Down
14 changes: 14 additions & 0 deletions src/create_embedded_tools.sh
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ for i in $*; do
*xcode*xcode-locator) OUTPUT_PATH=tools/objc/xcode-locator ;;
*src/tools/xcode/*.sh) OUTPUT_PATH=tools/objc/${i##*/} ;;
*src/tools/xcode/*) OUTPUT_PATH=tools/objc/${i##*/}.sh ;;
*external/openjdk_*/file/*.tar.gz) OUTPUT_PATH=jdk.tar.gz ;;
*external/openjdk_*/file/*.zip) OUTPUT_PATH=jdk.zip ;;
*) OUTPUT_PATH=$(echo $i | sed 's_^.*bazel-out/[^/]*/bin/__') ;;
esac

Expand All @@ -71,6 +73,18 @@ for i in $*; do
chmod u+w "${PACKAGE_DIR}/${OUTPUT_PATH}"
done

if [ -f ${PACKAGE_DIR}/jdk.tar.gz ]; then
tar xz -C ${PACKAGE_DIR} -f ${PACKAGE_DIR}/jdk.tar.gz
rm ${PACKAGE_DIR}/jdk.tar.gz
mv ${PACKAGE_DIR}/zulu* ${PACKAGE_DIR}/jdk
fi

if [ -f ${PACKAGE_DIR}/jdk.zip ]; then
unzip -d ${PACKAGE_DIR} ${PACKAGE_DIR}/jdk.zip > /dev/null
rm ${PACKAGE_DIR}/jdk.zip
mv ${PACKAGE_DIR}/zulu* ${PACKAGE_DIR}/jdk
fi

if [ ! -f ${PACKAGE_DIR}/third_party/java/jdk/langtools/javac-9-dev-r3297-4.jar ]; then
cp ${PACKAGE_DIR}/third_party/java/jdk/langtools/javac7.jar \
${PACKAGE_DIR}/third_party/java/jdk/langtools/javac-9-dev-r3297-4.jar
Expand Down
12 changes: 11 additions & 1 deletion src/main/cpp/startup_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,19 @@ string StartupOptions::GetDefaultHostJavabase() const {
}

string StartupOptions::GetHostJavabase() {
// 1) Allow overriding the host_javabase via --host_javabase.
if (host_javabase.empty()) {
if (default_host_javabase.empty()) {
default_host_javabase = GetDefaultHostJavabase();
string bundled_jre_path = blaze_util::JoinPath(
install_base, "_embedded_binaries/embedded_tools/jdk");
if (blaze_util::CanExecuteFile(blaze_util::JoinPath(
bundled_jre_path, GetJavaBinaryUnderJavabase()))) {
// 2) Use a bundled JVM if we have one.
default_host_javabase = bundled_jre_path;
} else {
// 3) Otherwise fall back to using the default system JVM.
default_host_javabase = GetDefaultHostJavabase();
}
}

return default_host_javabase;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@
// limitations under the License.
package com.google.devtools.build.lib.runtime.commands;

import com.google.common.io.Files;
import com.google.devtools.build.lib.analysis.NoBuildEvent;
import com.google.devtools.build.lib.runtime.BlazeCommand;
import com.google.devtools.build.lib.runtime.Command;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.util.ExitCode;
import com.google.devtools.build.lib.util.ResourceFileLoader;
import com.google.devtools.build.lib.util.io.OutErr;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsProvider;
import java.io.IOException;
import java.util.TreeSet;

/** A command that prints an embedded license text. */
@Command(
Expand All @@ -34,6 +37,16 @@
)
public class LicenseCommand implements BlazeCommand {

private static final TreeSet<String> JAVA_LICENSE_FILES =
new TreeSet<>(String.CASE_INSENSITIVE_ORDER);

static {
JAVA_LICENSE_FILES.add("ASSEMBLY_EXCEPTION");
JAVA_LICENSE_FILES.add("DISCLAIMER");
JAVA_LICENSE_FILES.add("LICENSE");
JAVA_LICENSE_FILES.add("THIRD_PARTY_README");
}

public static boolean isSupported() {
return ResourceFileLoader.resourceExists(LicenseCommand.class, "LICENSE");
}
Expand All @@ -52,9 +65,41 @@ public ExitCode exec(CommandEnvironment env, OptionsProvider options) {
"I/O error while trying to print 'LICENSE' resource: " + e.getMessage(), e);
}

Path bundledJdk =
env.getDirectories().getEmbeddedBinariesRoot().getRelative("embedded_tools/jdk");
if (bundledJdk.exists()) {
outErr.printOutLn(
"This binary comes with a bundled JDK, which contains the following license files:\n");
printJavaLicenseFiles(outErr, bundledJdk);
}

Path bundledJre =
env.getDirectories().getEmbeddedBinariesRoot().getRelative("embedded_tools/jre");
if (bundledJre.exists()) {
outErr.printOutLn(
"This binary comes with a bundled JRE, which contains the following license files:\n");
printJavaLicenseFiles(outErr, bundledJre);
}

return ExitCode.SUCCESS;
}

private static void printJavaLicenseFiles(OutErr outErr, Path bundledJdkOrJre) {
try {
for (Path path : bundledJdkOrJre.getDirectoryEntries()) {
if (JAVA_LICENSE_FILES.contains(path.getBaseName().toLowerCase())) {
outErr.printOutLn(path.getPathString() + ":\n");
Files.copy(path.getPathFile(), outErr.getOutputStream());
outErr.printOutLn("\n");
}
}
} catch (IOException e) {
throw new IllegalStateException(
"I/O error while trying to print license file of bundled JDK or JRE: " + e.getMessage(),
e);
}
}

@Override
public void editOptions(CommandEnvironment env, OptionsParser optionsParser) {}
}
10 changes: 10 additions & 0 deletions src/test/shell/bazel/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,16 @@ sh_test(
data = [":test-deps"],
)

sh_test(
name = "bazel_with_jdk_test",
size = "medium",
srcs = ["bazel_with_jdk_test.sh"],
data = [
":test-deps",
"//src:bazel_with_jdk",
],
)

sh_test(
name = "build_files_test",
size = "medium",
Expand Down
77 changes: 77 additions & 0 deletions src/test/shell/bazel/bazel_with_jdk_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/bin/bash
#
# Copyright 2017 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.
#
# Tests that the version of Bazel with a bundled JDK works.
#

# Load the test setup defined in the parent directory
source $(rlocation io_bazel/src/test/shell/integration_test_setup.sh) \
|| { echo "integration_test_setup.sh not found!" >&2; exit 1; }

function bazel_with_jdk() {
$(rlocation io_bazel/src/bazel_with_jdk) --bazelrc=$TEST_TMPDIR/bazelrc "$@"
return $?
}

function set_up() {
# TODO(philwo) remove this when the testenv improvement change is in
if is_windows; then
export PATH=/c/python_27_amd64/files:$PATH
EXTRA_BAZELRC="build --cpu=x64_windows_msvc"
setup_bazelrc
fi

# The default test setup adds a --host_javabase flag, which prevents us from
# actually using the bundled one. Remove it.
fgrep -v -- "--host_javabase" "$TEST_TMPDIR/bazelrc" > "$TEST_TMPDIR/bazelrc.new"
mv "$TEST_TMPDIR/bazelrc.new" "$TEST_TMPDIR/bazelrc"
}

function cleanup() {
# Prevent the default "cleanup" function from running, which fails on Windows.
return 0
}

function test_bazel_uses_bundled_jdk() {
bazel_with_jdk --batch info &> "$TEST_log" || fail "bazel_with_jdk info failed"
install_base="$(bazel_with_jdk --batch info install_base)"

# Case-insensitive match, because Windows paths are case-insensitive.
grep -sqi -- "^java-home: ${install_base}/_embedded_binaries/embedded_tools/jdk" $TEST_log || \
fail "bazel_with_jdk's java-home is not inside the install base"
}

# Tests that "bazel_with_jdk license" prints the license of the bundled JDK by grepping for
# representative strings from those files. If this test breaks after upgrading the version of the
# bundled JDK, the strings may have to be updated.
function test_bazel_license_prints_jdk_license() {
bazel_with_jdk --batch license \
&> "$TEST_log" || fail "running bazel_with_jdk license failed"

expect_log "OPENJDK ASSEMBLY EXCEPTION" || \
fail "'bazel_with_jdk license' did not print an expected string from ASSEMBLY_EXCEPTION"

expect_log "Provided you have not received the software directly from Azul and have already" || \
fail "'bazel_with_jdk license' did not print an expected string from DISCLAIMER"

expect_log '"CLASSPATH" EXCEPTION TO THE GPL' || \
fail "'bazel_with_jdk license' did not print an expected string from LICENSE"

expect_log "which may be included with JRE [0-9]\+, JDK [0-9]\+, and OpenJDK [0-9]\+" || \
fail "'bazel_with_jdk license' did not print an expected string from THIRD_PARTY_README"
}

run_suite "bazel_with_jdk test suite"

0 comments on commit 9504827

Please sign in to comment.