| #!/usr/bin/env bash |
| |
| # Copyright 2025 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. |
| |
| # This script creates from the full JDK a minimized version that only contains |
| # the specified JDK modules. |
| |
| # --- begin runfiles.bash initialization v3 --- |
| # Copy-pasted from the Bazel Bash runfiles library v3. |
| set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash |
| # shellcheck disable=SC1090 |
| source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ |
| source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ |
| source "$0.runfiles/$f" 2>/dev/null || \ |
| source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ |
| source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ |
| { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e |
| # --- end runfiles.bash initialization v3 --- |
| |
| # Force a UTF-8 compatible locale for Java tools to operate under paths with |
| # Unicode characters. |
| if [[ $(locale charmap) != "UTF-8" ]]; then |
| export LC_CTYPE=C.UTF-8 |
| fi |
| if [[ $(locale charmap) != "UTF-8" ]]; then |
| export LC_CTYPE=en_US.UTF-8 |
| fi |
| |
| if [ "$1" == "--allmodules" ]; then |
| shift |
| modules="ALL-MODULE-PATH" |
| else |
| modules=$(cat "$3" | paste -sd "," - | tr -d '\r') |
| # We have to add this module explicitly because jdeps doesn't find the |
| # dependency on it but it is still necessary for TLSv1.3. |
| modules="$modules,jdk.crypto.ec" |
| fi |
| tooljdk=$1 |
| fulljdk=$2 |
| out=$4 |
| # Optional 5th argument: a separate jmods archive for JDKs that don't ship |
| # with jmods (e.g. Adoptium Temurin with JEP 493 enabled). |
| jmods_archive=${5:-} |
| # Convert to absolute path since we cd later. |
| if [ -n "$jmods_archive" ]; then |
| jmods_archive=$(cd "$(dirname "$jmods_archive")" && echo "$(pwd)/$(basename "$jmods_archive")") |
| fi |
| |
| UNAME=$(uname -s | tr 'A-Z' 'a-z') |
| # Options for the JVM that runs the Bazel server, which are either required or |
| # recommended when using the embedded JDK on platforms that use a minified JDK. |
| # Setting these options here rather than in blaze.cc avoids the need to detect |
| # compatible JDKs. |
| # Native access is required for the JNI library. |
| # Compact object headers reduce retained and peak memory usage. |
| JVM_OPTIONS='--enable-native-access=ALL-UNNAMED -XX:+UseCompactObjectHeaders' |
| |
| # Strips an extracted JDK archive to its home directory. |
| # Some JDK archives (e.g., macOS .jdk bundles) nest the JDK home inside |
| # additional directories like Contents/Home/. This function detects the |
| # actual JDK home by locating the 'release' file and moves it to the |
| # expected top-level directory. |
| strip_to_jdk_home() { |
| local dir=$1 |
| local release |
| release=$(find "$dir" -name release -maxdepth 4 -print -quit) |
| if [[ -z "$release" ]]; then |
| echo "ERROR: could not find 'release' file in $dir" >&2 |
| exit 1 |
| fi |
| local jdk_home |
| jdk_home=$(dirname "$release") |
| if [[ "$jdk_home" != "$dir" ]]; then |
| local tmp="${dir}_tmp" |
| mv "$jdk_home" "$tmp" |
| rm -rf "$dir" |
| mv "$tmp" "$dir" |
| fi |
| } |
| |
| if [[ "$UNAME" =~ msys_nt* ]]; then |
| unzip -q "$tooljdk" -d "tool_jdk.$$" |
| strip_to_jdk_home "tool_jdk.$$" |
| unzip -q "$fulljdk" -d "full_jdk.$$" |
| strip_to_jdk_home "full_jdk.$$" |
| tool_jdk_home=$(cd "tool_jdk.$$" && pwd) |
| cd "full_jdk.$$" |
| # If the full JDK doesn't ship with jmods (e.g. JEP 493), use the separately |
| # provided jmods archive. |
| if [ ! -f jmods/java.base.jmod ]; then |
| if [ -n "$jmods_archive" ]; then |
| unzip -q "$jmods_archive" -d jmods_tmp |
| # The archive contains a single top-level directory with jmod files. |
| mv jmods_tmp/*/* jmods_tmp/ 2>/dev/null || true |
| # Move all .jmod files into the jmods directory. |
| mkdir -p jmods |
| mv jmods_tmp/*.jmod jmods/ |
| rm -rf jmods_tmp |
| else |
| echo >&2 "ERROR: Full JDK does not contain jmods/java.base.jmod and no" \ |
| "separate jmods archive was provided. Cross-jlinking requires jmods." \ |
| "JDKs with JEP 493 enabled (e.g. Adoptium Temurin 24+) need a separate" \ |
| "jmods download." |
| exit 1 |
| fi |
| fi |
| # We have to add this module explicitly because it is windows specific, it allows |
| # the usage of the Windows truststore |
| # e.g. -Djavax.net.ssl.trustStoreType=WINDOWS-ROOT |
| modules="$modules,jdk.crypto.mscapi" |
| "$tool_jdk_home/bin/jlink" --module-path ./jmods/ --add-modules "$modules" \ |
| --vm=server --strip-debug --no-man-pages --no-header-files \ |
| --add-options=" ${JVM_OPTIONS}"\ |
| --output reduced |
| # Patch the app manifest of the java.exe launcher to force its active code |
| # page to UTF-8 on Windows 1903 and later, which is required for proper |
| # support of Unicode characters outside the system code page. |
| # The JDK currently (as of JDK 23) doesn't support this natively: |
| # https://mail.openjdk.org/pipermail/core-libs-dev/2024-November/133773.html |
| "$(rlocation io_bazel/src/read_manifest.exe)" reduced/bin/java.exe \ |
| | sed 's|</asmv3:windowsSettings>|<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>&|' \ |
| | "$(rlocation io_bazel/src/write_manifest.exe)" reduced/bin/java.exe |
| for f in DISCLAIMER readme.txt legal/java.base/ASSEMBLY_EXCEPTION; do [ -f "$f" ] && cp "$f" reduced/; done |
| # These are necessary for --host_jvm_debug to work. |
| cp bin/dt_socket.dll bin/jdwp.dll reduced/bin |
| zip -q -X -r ../reduced.zip reduced/ |
| cd .. |
| mv reduced.zip "$out" |
| rm -rf "full_jdk.$$" "tool_jdk.$$" |
| else |
| # The --no-same-owner flag instructs tar to not try to chown extracted files |
| # to the owner stored in the archive - it will try to do that when running as |
| # root, but fail when running inside Docker, so we explicitly disable it. |
| mkdir "tool_jdk.$$" |
| tar xf "$tooljdk" --no-same-owner -C "tool_jdk.$$" |
| strip_to_jdk_home "tool_jdk.$$" |
| mkdir "target_jdk.$$" |
| tar xf "$fulljdk" --no-same-owner -C "target_jdk.$$" |
| strip_to_jdk_home "target_jdk.$$" |
| cd "target_jdk.$$" |
| # If the full JDK doesn't ship with jmods (e.g. JEP 493), use the separately |
| # provided jmods archive. |
| if [ ! -f jmods/java.base.jmod ]; then |
| if [ -n "$jmods_archive" ]; then |
| mkdir -p jmods |
| tar xf "$jmods_archive" --no-same-owner --strip-components=1 -C jmods --wildcards '*.jmod' |
| else |
| echo >&2 "ERROR: Full JDK does not contain jmods/java.base.jmod and no" \ |
| "separate jmods archive was provided. Cross-jlinking requires jmods." \ |
| "JDKs with JEP 493 enabled (e.g. Adoptium Temurin 24+) need a separate" \ |
| "jmods download." |
| exit 1 |
| fi |
| fi |
| "../tool_jdk.$$/bin/jlink" --module-path ./jmods/ --add-modules "$modules" \ |
| --vm=server --strip-debug --no-man-pages --no-header-files \ |
| --add-options=" ${JVM_OPTIONS}" \ |
| --output reduced |
| for f in DISCLAIMER readme.txt legal/java.base/ASSEMBLY_EXCEPTION; do [ -f "$f" ] && cp "$f" reduced/; done |
| # These are necessary for --host_jvm_debug to work. |
| cp lib/libdt_socket.* lib/libjdwp.* reduced/lib |
| find reduced -exec touch -ht 198001010000 {} + |
| zip -q -X -r ../reduced.zip reduced/ |
| cd .. |
| mv reduced.zip "$out" |
| rm -rf "target_jdk.$$" "tool_jdk.$$" |
| fi |