Golang二进制文件通过Java的ProcessBuilder执行时缺少库但终端运行正常的解决方法

Golang二进制文件通过Java的ProcessBuilder执行时缺少库但终端运行正常的解决方法 各位Golang同好,大家好。我在尝试使用一个我修改并构建了二进制文件的Golang CLI应用程序时遇到了一个问题(构建和使用的系统是同一个)。这个程序确实需要gl包,我认为正是这个包导致了这个问题。

我是这样构建程序的(justfile语法):

# runs the golang build
build label=(name + '-' + version) goos=os() archh=arch():
    #!/usr/bin/env bash
    set -euo pipefail
 
    env \
        `# set enviroment variables`
        GOOS={{ goos }} \
        GOARCH={{ archh }} \
    `# build the program`
    go build \
        -o {{ label }}-{{ goos }}-{{ archh }}

当从终端调用时(./kami-linux -h),它可以正常工作,功能完全符合预期。但是,如果我通过Java的ProcessBuilder调用完全相同的命令,像这样:

val process = ProcessBuilder(
    "${File(".").canonicalPath}/kami-linux",
    "-h"
)
    .redirectInput(ProcessBuilder.Redirect.PIPE)
    .redirectOutput(ProcessBuilder.Redirect.PIPE)
    .redirectError(ProcessBuilder.Redirect.INHERIT)
    .start()

我会得到:

.../kami-linux: /usr/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by .../kami-linux)

这是继承了进程的错误流的结果。

我四处查找,看到了一个类似的问题,建议运行strings /usr/lib/x86_64-linux-gnu/libc.so.6 | grep GLIBC(路径已修改)。在我的情况下,运行这个命令得到:

GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_2.13
GLIBC_2.14
GLIBC_2.15
GLIBC_2.16
GLIBC_2.17
GLIBC_2.18
GLIBC_2.22
GLIBC_2.23
GLIBC_2.24
GLIBC_2.25
GLIBC_2.26
GLIBC_2.27
GLIBC_2.28
GLIBC_2.29
GLIBC_2.30
GLIBC_2.32
GLIBC_PRIVATE
GNU C Library (Ubuntu GLIBC 2.32-0ubuntu3) release release version 2.32.

这表明我确实有正确的版本。作为一个Golang和Linux新手,我对此毫无头绪。

这是相关的完整项目:

GitHub GitHub

Avatar

DeflatedPickle/KAMI

通过在GitHub上创建一个帐户来为DeflatedPickle/KAMI的开发做出贡献。

我估计这只是我犯傻了,但我将非常感谢任何尝试解决这个问题的建议。


更多关于Golang二进制文件通过Java的ProcessBuilder执行时缺少库但终端运行正常的解决方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang二进制文件通过Java的ProcessBuilder执行时缺少库但终端运行正常的解决方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这个问题是由于Java的ProcessBuilder执行环境与终端环境不同导致的。Golang二进制文件在构建时可能动态链接了系统库,而Java进程的环境变量(特别是LD_LIBRARY_PATH)可能未正确设置。

以下是解决方案:

  1. 使用静态编译:在构建Golang程序时添加CGO_ENABLED=0环境变量,强制静态链接所有依赖。
env \
    CGO_ENABLED=0 \
    GOOS={{ goos }} \
    GOARCH={{ archh }} \
go build \
    -o {{ label }}-{{ goos }}-{{ archh }}
  1. 指定动态链接器路径:如果必须使用动态链接,可以在Java中设置环境变量。
Map<String, String> env = processBuilder.environment();
env.put("LD_LIBRARY_PATH", "/usr/lib/x86_64-linux-gnu");

Process process = new ProcessBuilder(
    "${File(".").canonicalPath}/kami-linux",
    "-h"
)
    .redirectInput(ProcessBuilder.Redirect.PIPE)
    .redirectOutput(ProcessBuilder.Redirect.PIPE)
    .redirectError(ProcessBuilder.Redirect.INHERIT)
    .start();
  1. 使用完整路径执行:确保Java进程的工作目录正确。
Process process = new ProcessBuilder(
    new File(".").getCanonicalPath() + "/kami-linux",
    "-h"
)
    .directory(new File("."))  // 显式设置工作目录
    .redirectInput(ProcessBuilder.Redirect.PIPE)
    .redirectOutput(ProcessBuilder.Redirect.PIPE)
    .redirectError(ProcessBuilder.Redirect.INHERIT)
    .start();
  1. 检查glibc版本兼容性:构建时指定较低版本的glibc。
env \
    CGO_CFLAGS="-g -O2 -Wl,--no-as-needed" \
    GOOS={{ goos }} \
    GOARCH={{ archh }} \
go build \
    -ldflags="-linkmode external -extldflags -static" \
    -o {{ label }}-{{ goos }}-{{ archh }}

静态编译是最可靠的解决方案,可以避免运行时依赖问题。修改构建脚本后重新编译,Java的ProcessBuilder应该能正常执行二进制文件。

回到顶部