返回

构建静态链接或大部分静态链接的本地可执行文件

GraalVM Native Image 默认构建动态链接的二进制文件:在构建时,它首先加载应用程序的类和接口,然后通过动态链接的过程将它们关联起来。

但是,您可以根据需要创建静态链接或大部分静态链接的本地可执行文件。

静态本地可执行文件是一个静态链接的二进制文件,无需任何额外的库依赖即可使用。静态本地可执行文件易于分发和部署到精简或无发行版容器(scratch 容器)上。您可以通过将其静态链接到 musl-libc 来创建静态本地可执行文件,musl-libc 是一个轻量级、快速且简单的 libc 实现。

大部分静态本地可执行文件是一个二进制文件,它链接了本地可执行文件所依赖的所有共享库(zlib、JDK 共享静态库),除了标准 C 库 libc。这是静态链接所有内容的另一种选择。此外,根据用户的代码,它可能链接 libstdc+libgcc。这种方法对于部署到无发行版容器镜像非常有用。

本指南展示了如何利用 Native Image 的链接选项,包括完全动态、完全静态和大部分静态(除了 libc),以生成适合您部署场景的可执行文件。

先决条件和准备

  • Linux x64 操作系统
  • Java 17 或更高版本的 GraalVM 发行版
  • 64 位 musl 工具链、makeconfigure
  • 最新的 zlib

确保您已安装 GraalVM JDK。最简单的入门方法是使用 SDKMAN!。有关其他安装选项,请访问下载部分

要使用 Native Image 创建静态链接应用程序,您需要一个包含 zlib 库的 musl 工具链。请使用最新或较新版本的 musl(所有早于或包括 1.2.5 的版本都受 CVE-2025-26519 影响)。从 源代码 构建 musl 的步骤如下所示。本示例假设您使用的是 musl-1.2.6

# Specify an installation directory for musl:
export MUSL_HOME=$PWD/musl-toolchain

# Download musl and zlib sources:
curl -O https://musl.libc.org/releases/musl-1.2.6.tar.gz
curl -O https://zlib.net/fossils/zlib-1.2.13.tar.gz

# Build musl from source
tar -xzvf musl-1.2.6.tar.gz
pushd musl-1.2.6
./configure --prefix=$MUSL_HOME --static
# The next operation may require privileged access to system resources, so use sudo
sudo make && make install
popd

# Install a symlink for use by native-image
ln -s $MUSL_HOME/bin/musl-gcc $MUSL_HOME/bin/x86_64-linux-musl-gcc

# Extend the system path and confirm that musl is available by printing its version
export PATH="$MUSL_HOME/bin:$PATH"
x86_64-linux-musl-gcc --version

# Build zlib with musl from source and install into the MUSL_HOME directory
tar -xzvf zlib-1.2.13.tar.gz
pushd zlib-1.2.13
CC=musl-gcc ./configure --prefix=$MUSL_HOME --static
make && make install
popd

设置好要求后,按如下所示创建演示。

构建静态本地可执行文件

  1. 将以下源代码保存到名为 EnvMap.java 的文件中
     import java.util.Map;
    
     public class EnvMap {
         public static void main (String[] args) {
             var filter = args.length > 0 ? args[0] : "";
             Map<String, String> env = System.getenv();
             for (String envName : env.keySet()) {
                 if(envName.contains(filter)) {
                     System.out.format("%s=%s%n",
                                     envName,
                                     env.get(envName));
                 }
             }
         }
     }
    

    此应用程序会遍历您的环境变量,并打印出包含作为命令行参数传递的字符串的环境变量。

  2. 编译应用程序
     javac EnvMap.java
    
  3. 通过运行此命令构建静态本地可执行文件
     native-image --static --libc=musl EnvMap
    

    这将生成一个带有静态链接系统库的本地可执行文件。使用 ./envmap 运行它。

    您可以使用 ldd 命令确认应用程序是否完全静态链接

     ldd EnvMap
    

    输出应为“not a dynamic executable”(不是动态可执行文件)。

构建大部分静态本地可执行文件

使用 GraalVM Native Image,您可以构建一个大部分静态的本地可执行文件,该文件静态链接除了 libc 之外的所有内容。静态链接除了 libc 之外的所有库可确保您的应用程序拥有在任何基于 Linux libc 的发行版上运行所需的所有库。

要构建大部分静态本地可执行文件,请使用此命令

native-image --static-nolibc [other arguments] <Class>

要为上述 EnvMap 演示构建大部分静态本地可执行文件,请运行

native-image --static-nolibc EnvMap

这将生成一个本地可执行文件,它静态链接了所有相关库(包括 JDK 共享静态库),除了 libc。这包括 zlib。此外,根据用户的代码,它可能链接 libstdc+libgcc。检查您的应用程序依赖哪些动态库的一种方法是使用本地可执行文件运行 ldd,例如,ldd envmap

常见问题

完全静态的本地可执行文件为您选择基础容器镜像提供了最大的灵活性——它甚至可以在 scratch 镜像上运行。大部分静态的本地可执行文件需要提供 libc(特别是 glibc)的容器镜像,但没有额外的要求。在这两种情况下,选择基础容器镜像通常取决于您的本地可执行文件的具体要求。

  • Tiny Java Containers 演示展示了如何编译一个简单的 Java 应用程序和一个简单的 Web 服务器,以使用各种轻量级基础镜像生成非常小的 Docker 容器镜像。
  • GraalVM Native Image、Spring 和容器化 交互式实验,用于构建 Spring Boot 应用程序的大部分静态可执行文件。

联系我们