在 Java 中决定 linux 的 GNU 或 MUSL 版本

Decide GNU or MUSL build of linux in Java

我有一个 Java 桌面应用程序,它应该在 GNU Linux 发行版(Debian 和 Ubuntu)和 MUSL Linux 发行版中 运行 (高山)。我的应用程序也使用本机库,并且本机库构建对于两种类型的 Linux 发行版都是不同的。

我将在不同的文件夹中随我的应用程序一起交付。因此在 运行 时间 Java 程序需要根据 Linux(GNU 或 MUSL)选择正确的本地库分布。

我没有找到任何机制来了解 Java 程序,Linux 发行版 JVM 运行正在运行。

我正在考虑从 Linux 的 /etc/ 文件夹中读取 OS 文件的一种方法。但我认为这不是一个好的解决方案(因为某些自定义构建可能会更改此细节),有人可以针对此问题提出一些更好的解决方案吗?或者如何做到这一点?

您可以通过关注 this Whosebug answer

来检测哪个 Linux 分布是 运行

遗憾的是,没有那么多替代方法可以检测您是 运行 MUSL 还是 GLIBC

使用Java/JNA,您可以映射gnu_get_libc_version()函数并在加载libc后尝试执行它。如果它有效,那么你就在使用 glibc (GNU)。如果您收到 UnsatisfiedLinkError 表示未找到该函数,则说明您使用的是其他 libc。

映射函数:

public interface Libc extends Library {
    Libc INSTANCE = Native.load("c", Libc.class);

    String gnu_get_libc_version();
}

称呼它:

public class GnuOrMusl {
    public static void main(String[] args) {
        try {
            System.out.println("On GNU libc version " + Libc.INSTANCE.gnu_get_libc_version());
        } catch (UnsatisfiedLinkError e) {
            System.out.println("Not on glibc!");
        }
    }
}

可能有类似的方法具有独特的功能来区分其他 libc 变体与 MUSL,但据我所知,MUSL 试图与标准兼容,以至于它实际上不允许识别自己。


查找 GNU 发行版的另一个选项是 uname -o 您可以使用 ProcessBuilder 执行的命令。

在非 GNU (Alpine) 上它只是“Linux”,而在 Ubuntu、Debian 和 OpenSUSE 上它是“GNU/Linux”。


您还可以通过遍历 /lib* 目录查找 libc 变体来成功确定 GNU 与 MUSL。这类似于 when compiling the JDK 所采用的方法,它执行 ldd 命令并从该输出中解析库。

例如,在 Alpine linux 中迭代 /lib 目录得到这个 link:libc.musl-x86_64.so.1 -> ld-musl-x86_64.so.1

在 Debian /lib32 中有 libc.so.6 -> libc-2.28.so,在 OpenSUSE /lib64 中我看到类似的东西:libc.so.6 -> libc-2.26.so,Ubuntu /lib/aarch64-linux-gnulibc-2.27.so.

如果您停留在 Java 范围内,确定要搜索的 /lib 路径可能需要反复试验。解析命令行的输出,例如 ldd `which ls` 可能会得到一个包含 gnumusl.

的字符串

就确定使用哪个 Linux 发行版而言,从 /etc 文件夹中读取是一个很好的直觉。我负责管理基于 Java 的操作系统和硬件信息 (OSHI) 项目,并通过几乎所有选项来确定您是哪个发行版 运行。您可以在 this class.

中看到所有这些工作的结果

我将在该文件中引用一条评论:

There are two competing options for family/version information. Newer systems are adopting a standard /etc/os-release file: https://www.freedesktop.org/software/systemd/man/os-release.html

Some systems are still using the lsb standard which parses a variety of /etc/*-release files and is most easily accessed via the commandline lsb_release -a, see here: https://linux.die.net/man/1/lsb_release In this case, the /etc/lsb-release file (if it exists) has optional overrides to the information in the /etc/distrib-release files, which show: "Distributor release x.x (Codename)"

代码的逻辑是:

  1. 尝试/etc/system-release
  2. 尝试/etc/os-release
  3. 运行 lsb_release 命令
  4. 阅读/etc/lsb-release
  5. 查找并阅读任何 /etc/*-release 文件。

这些文件包含 NAME 之类的键,可以帮助您解决问题。

随意复制和使用该文件或变体,或者仅将该项目用作依赖项。