【问题标题】:Problem loading shared library using dyn.load on R Linux, but equivalent Windows build works fine在 R Linux 上使用 dyn.load 加载共享库时出现问题,但等效的 Windows 构建工作正常
【发布时间】:2019-12-08 07:32:38
【问题描述】:

我已经构建了一个 package 用于与 R 中的 HDFql 交互。它依赖于 HDFql 2.1.0 提供的 R 包装器和 DLL/SO。这些包使用 DLL 在 Windows 中完美运行,但由于某种原因,HDFql 库 SO 无法在 Linux 环境中加载。我在 Travis 和本地 Docker Linux/R 容器上都试过了。

函数hql_load()中包含的相关代码如下。假设HDFql被解压到当前目录“/hdfql-2.1.0”的一个文件夹中,也就是说

dllpath = c("/hdfql-2.1.0/lib/libHDFql.so", "/hdfql-2.1.0/wrapper/R/libHDFqlR.so")

我使用normalizePath(dllpath, mustWork = TRUE) 检查这些路径是否存在,并检查对象是否成功加载并出现在getLoadedDlls() 中。

# ... starting at line 153 of connect.r ... #
wrapper.file = tempfile(fileext = ".r")
  wrapper.lines = readLines(wrapperpath)
  writeLines(wrapper.lines[-grep("dyn\\.load", wrapper.lines)],
    wrapper.file)
  # load DLLs
  for (dll in dllpath) {
    dyn.load(dll, local = FALSE, now = TRUE)
    if (!dll %in% sapply(getLoadedDLLs(), function(x) normalizePath(x[["path"]], mustWork = FALSE))) {
      stop("Error loading HDFql shared library object ", dll)
    } 
  }
  # load wrapper
  wrapper = new.env(parent = .BaseNamespaceEnv)
  tryCatch(
    sys.source(wrapper.file, envir = wrapper, toplevel.env = packageName()),
    error = function(e) {
      stop("Failed to execute HDFql R wrapper.\n Additional Information:\n",
       e)
    }
  )
  assign("wrapper", wrapper, envir = hql)
  invisible(NULL)
}

错误发生在 sys.source 调用以评估 HDFql 提供的包装文件中的代码,特别是在初始化调用中。包装内容如下;请注意,在我上面的函数中,我在评估之前从包装器中删除了 dyn.load 调用(预先加载了库)。

hdfql_operating_system = Sys.info()["sysname"]
if (hdfql_operating_system == "Windows")
{
    dyn.load("HDFqlR.dll")
    hdfql_shared_library <- "HDFqlR"
} else if (hdfql_operating_system == "Linux")
{
    dyn.load("libHDFqlR.so")
    hdfql_shared_library <- "libHDFqlR"
} else   # macOS
{
    dyn.load("libHDFqlR.dylib")
    hdfql_shared_library <- "libHDFqlR.dylib"
}
rm(hdfql_operating_system)



#===========================================================
# INITIALIZE HDFQL R WRAPPER SHARED LIBRARY
#===========================================================
hdfql_initialize_status = .Call("_hdfql_initialize", PACKAGE = hdfql_shared_library)

错误:无法执行 HDFql R 包装器。

附加信息:

eval 中的错误(解析(wrapper.file),envir = wrapper):找不到/加载 HDFql 共享库“libHDFql.so”!

我已经对此进行了数周的故障排除,但进展甚微。谁能告诉我为什么库在 Linux 系统中不能正确加载?

【问题讨论】:

  • 错误信息是什么?您是否已将 SO 文件的位置添加到 LD_LIBRARY_PATH
  • @RalfStubner 我用错误消息更新了我的帖子,这很模糊。你能解释一下LD_LIBRARY_PATH的用法吗? HDFql 包装器说明未讨论此设置,我的理解是LD_LIBRARY_PATH 用于包中包含或构建的 DLL。 HDFql 库没有随包一起安装;它是一个外部程序。该包使用dyn.load 和访问共享库的完整路径。
  • @RalfStubner 实际上我现在看到 LD_LIBRARY_PATHS 在 HDFql 手册中进行了讨论。我会查看是否可以解决问题。

标签: r shared-libraries hdfql


【解决方案1】:

@RalfStubner 的建议是正确的:问题是在 Linux 机器上设置 LD_LIBRARY_PATH 以包含 HDFql 库。有趣的是,我仍然必须在 dyn.load 调用中为 DLL 提供完整的限定路径名,并且不能使用 Sys.setenvdyn.loadDLLpath 参数来临时修改 LD_LIBRARY_PATH——而是我已在我的travis.yaml/Dockerfile 中添加一行以更新LD_LIBRARY_PATH

export LD_LIBRARY_PATH=${HDFQL_DIR}/lib:${HDFQL_DIR}/wrapper/R:$LD_LIBRARY_PATH

我仍然不明白为什么我无法使用例如解决问题

Sys.setenv(LD_LIBRARY_PATH = paste(dirname(dll), Sys.getenv("LD_LIBRARY_PATH"), sep = ":")

dyn.load(basename(dll), DLLpath = dirname(dll))

因为这两个命令都应该(理论上)修改搜索路径以包含 HDFql 目录。 我将不胜感激任何可以解释这一点的答案。

我还惊讶地发现,在更新 LD_LIBRARY_PATH 后,我遇到了 Windows 构建中从未出现过的环境绑定和命名空间问题——但这是一个单独的问题。

【讨论】:

    猜你喜欢
    • 2023-03-31
    • 2020-01-15
    • 1970-01-01
    • 2010-11-13
    • 2013-07-10
    • 1970-01-01
    • 1970-01-01
    • 2020-09-15
    • 1970-01-01
    相关资源
    最近更新 更多