You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby:如何用FFI::Library卸载或指定.so库?(Ethon+libcurl场景)

问题:如何通过猴补丁解决FFI调用自定义libcurl函数的库优先级问题

我使用Ethon gem加载libcurl库,gem内的加载代码如下:

ffi_lib_flags :now, :global
ffi_lib ['libcurl.so', 'libcurl.so.4']
extend Ethon::Curls::Functions # 从libcurl绑定函数

我编写的猴补丁代码:

ffi_lib_flags :now, :global
ffi_lib '/home/myuser/libs/libcurl.so'
attach_function :easy_impersonate, :curl_easy_impersonate, [:pointer, :string, :int], :int # 绑定自定义libcurl中的函数
extend Ethon::Curls::Functions # 从自定义libcurl绑定默认函数

FFI能找到curl_easy_impersonate函数,但调用时返回错误码48(根据libcurl文档,该错误码表示未找到对应函数)。不过如果直接修改gem中的ffi_lib ['libcurl.so', 'libcurl.so.4']为ffi_lib '/home/myuser/libs/libcurl.so',调用该函数会返回0并正常工作。推测原因是FFI优先使用了gem加载的系统默认libcurl库。

核心问题:是否可以通过FFI卸载已加载的库,或者显式指定函数调用时使用的库?

补充要求:希望通过猴补丁实现,不想fork该gem(会增加生产环境维护成本)。已尝试移除附加的方法、通过ffi_libraries方法查找libcurl库对象并移除,但未找到相关痕迹。


解决方案

方法1:替换Ethon的库加载路径(推荐)

直接修改Ethon内部的库加载配置,让它优先加载你的自定义libcurl,而不是系统库。可以通过猴补丁覆盖Ethon的ffi_lib调用:

module Ethon
  module Curls
    module Functions
      remove_const(:LIBPATH) if defined?(LIBPATH)
      LIBPATH = ['/home/myuser/libs/libcurl.so']
      ffi_lib LIBPATH
    end
  end
end

# 重新绑定所有函数(包括你的自定义函数)
module Ethon
  module Curls
    module Functions
      attach_function :easy_impersonate, :curl_easy_impersonate, [:pointer, :string, :int], :int
    end
  end
end

原理是直接替换Ethon内部存储库路径的常量,让后续的函数绑定都指向你的自定义库。

方法2:显式指定函数的库来源

FFI允许在attach_function时通过:library参数指定使用哪个库对象。你可以先获取自定义库的对象,再绑定函数时指定它:

# 加载自定义库并获取库对象
custom_lib = FFI::Library.new
custom_lib.ffi_lib_flags :now, :global
custom_lib.ffi_lib '/home/myuser/libs/libcurl.so'

# 绑定自定义函数时指定库
attach_function :easy_impersonate, :curl_easy_impersonate, [:pointer, :string, :int], :int, library: custom_lib

# 重新绑定Ethon的默认函数到自定义库
module Ethon
  module Curls
    module Functions
      # 先移除已绑定的方法
      instance_methods.each do |m|
        remove_method(m) if m.to_s.start_with?('curl_')
      end
      # 从自定义库重新绑定所有函数
      custom_lib.extend(self)
    end
  end
end

这种方式强制让所有函数都使用你加载的自定义库,避免FFI的优先级问题。

方法3:调整系统库加载优先级(环境变量方式)

在启动Ruby进程前,设置LD_LIBRARY_PATH(Linux)或DYLD_LIBRARY_PATH(macOS),让系统优先加载你的自定义libcurl目录:

export LD_LIBRARY_PATH=/home/myuser/libs:$LD_LIBRARY_PATH
ruby your_script.rb

这种方式不需要修改代码,但需要确保部署环境的环境变量配置正确,适合无法修改代码的场景。


内容的提问来源于stack exchange,提问作者Вячеслав

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 18:21:32