【发布时间】:2021-02-24 19:59:15
【问题描述】:
作为起点,这段代码在 ruby 中工作到 2.2.5。对于较新的版本,它会返回“无法加载此类文件”。
require 'ffi'
module DllTest
extend FFI::Library
ENV['PATH'] = Dir.pwd + '\lib' + ';' + ENV['PATH']
ffi_lib 'bz2'
attach_function :version, 'BZ2_bzlibVersion', [], :string
end
puts DllTest.version
我从一个工作目录运行代码,该目录包含 lib 文件夹,其中包含 bz2.dll。问题是没有使用 PATH 环境变量。我可以指定库的绝对路径,它会工作,但还有另一个问题。我想使用加载不在同一目录中的其他库的库。我在 PATH 中指定了该目录,但由于某种原因它不起作用。我如何指定 PATH 并不重要。无论我事先在控制台中执行此操作,还是在上面的 ruby 脚本中执行此操作,我都会得到错误。
我真正想做的是我有使用 2 个 gem 安装的库。第一个 gem 安装核心库,第二个 gem 安装依赖于核心库的实际库。当 ruby 中需要库 gem 时,必要的库路径会以与示例代码中类似的方式加载到 PATH 中。这工作到 2.2.5
知道为什么会这样吗?
更基本的示例,仍然只适用于 ruby
test.rb:
require 'devkit'
require 'mkmf'
create_makefile 'foobar'
`make`
require_relative 'foobar'
ENV['PATH'] = (Dir.pwd + '\lib;').gsub('/', '\\') + ENV['PATH']
load_lib('bz2.dll')
foobar.c:
#include "ruby.h"
VALUE rb_load_lib(VALUE self, VALUE path)
{
HMODULE mod;
printf("%s\n\n", getenv("PATH"));
mod = LoadLibraryExA(RSTRING_PTR(path), NULL, 0);
printf("LoadLibraryExA: %s\n", mod != 0 ? "SUCCESS" : "FAIL");
return Qnil;
}
void Init_foobar()
{
rb_define_global_function("load_lib", rb_load_lib, 1);
}
【问题讨论】:
-
PATH 用于二进制文件,为什么你认为它适用于库?
-
PATH 环境变量按搜索顺序列出:docs.microsoft.com/en-us/windows/win32/dlls/…
-
在这种情况下,您需要确定是 windows 没有加载您的库还是 ffi 没有像 windows 那样使用 PATH,对吧?
-
我重建了 ffi gem C 部分。它调用 LoadLibraryEx(这是失败的确切函数),它应该使用 PATH 加载库及其依赖项。我之前插入了打印功能,它确实显示目录已插入 PATH。我不知道我还能检查什么。