如果 gem 安装不支持,本机扩展会回退到纯 Ruby

2024-05-03

我正在开发一个 gem,目前是纯 Ruby,但我也一直在为其中一个功能开发更快的 C 变体。该功能在纯 Ruby 中可用,但有时很慢。这种缓慢只会影响一些潜在用户(取决于他们需要哪些功能,以及他们如何使用这些功能),因此,如果 gem 无法在目标系统上编译,那么使用 gem 并优雅地回退到仅限 Ruby 的功能是有意义的。

我想在单个 gem 中维护该功能的 Ruby 和 C 变体,并在安装时提供 gem 的最佳(即最快)体验。这将使我能够从我的一个项目中支持最广泛的潜在用户。它还允许其他人的依赖 gem 和项目使用目标系统上的最佳可用依赖项,而不是为了兼容性而使用最低公分母版本。

我希望require在运行时回退以出现在主程序中lib/foo.rb文件就像这样:

begin
  require 'foo/foo_extended'
rescue LoadError
  require 'foo/ext_bits_as_pure_ruby'
end

但是,我不知道如何让 gem 安装来检查(或尝试并失败)本机扩展支持,以便 gem 安装正确,无论它是否可以构建“foo_extend”。当我研究如何做到这一点时,我主要发现了几年前的讨论,例如http://permalink.gmane.org/gmane.comp.lang.ruby.gems.devel/1479 http://permalink.gmane.org/gmane.comp.lang.ruby.gems.devel/1479 and http://rubyforge.org/pipermail/rubygems-developers/2007-November/003220.html http://rubyforge.org/pipermail/rubygems-developers/2007-November/003220.html这意味着 Ruby gems 并不真正支持此功能。不过最近没有什么,所以我希望 SO 上的人有一些更新的知识?

我理想的解决方案是在尝试构建扩展之前检测到目标 Ruby 不支持(或者在项目级别可能根本不想要)C 本机扩展。而且,如果不是太脏的话,try/catch 机制也可以。

这可能吗,如果可以的话怎么办?或者是建议发布两个 gem 变体(例如foo and foo_ruby),我在搜索时发现的,仍然是当前的最佳实践吗?


这是迄今为止我尝试回答自己的问题的最佳结果。它似乎适用于 JRuby(在 Travis 和 RVM 下的本地安装中进行了测试),这是我的主要目标。但是,我对它在其他环境中工作的确认非常感兴趣,以及有关如何使其更通用和/或更强大的任何输入:


gem 安装代码需要一个Makefile作为输出extconf.rb,但对其中应包含的内容没有意见。所以extconf.rb可以决定创建一个没做什么 Makefile,而不是调用create_makefile from mkmf。在实践中,可能看起来像这样:

分机/foo/extconf.rb

can_compile_extensions = false
want_extensions = true

begin
  require 'mkmf'
  can_compile_extensions = true
rescue Exception
  # This will appear only in verbose mode.
  $stderr.puts "Could not require 'mkmf'. Not fatal, the extensions are optional."
end


if can_compile_extensions && want_extensions
  create_makefile( 'foo/foo' )

else
  # Create a dummy Makefile, to satisfy Gem::Installer#install
  mfile = open("Makefile", "wb")
  mfile.puts '.PHONY: install'
  mfile.puts 'install:'
  mfile.puts "\t" + '@echo "Extensions not installed, falling back to pure Ruby version."'
  mfile.close

end

正如问题中所建议的,这个答案还需要以下逻辑来加载主库中的 Ruby 后备代码:

lib/foo.rb (摘录)

begin
  # Extension target, might not exist on some installations
  require 'foo/foo'
rescue LoadError
  # Pure Ruby fallback, should cover all methods that are otherwise in extension
  require 'foo/foo_pure_ruby'
end

遵循此路线还需要对 rake 任务进行一些调整,以便默认的 rake 任务不会尝试在我们正在测试的不具备编译扩展功能的 Rubies 上进行编译:

Rakefile(摘录)

def can_compile_extensions
  return false if RUBY_DESCRIPTION =~ /jruby/
  return true
end 

if can_compile_extensions
  task :default => [:compile, :test]
else
  task :default => [:test]
end

请注意Rakefile部分不必完全通用,它只需要覆盖我们想要在本地构建和测试 gem 的已知环境(例如所有 Travis 目标)。

我注意到一件令人烦恼的事情。默认情况下您将看到 Ruby Gems 的消息Building native extensions. This could take a while...,并且没有迹象表明扩展编译被跳过。但是,如果您使用以下命令调用安装程序gem install foo --verbose你确实看到消息被添加到extconf.rb,所以还不错。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如果 gem 安装不支持,本机扩展会回退到纯 Ruby 的相关文章

  • 如何阻止与 RSpec 和 Capybara 的外部连接?

    在我的 Rails 项目中 我想编写非理想条件的测试 例如缺乏互联网连接或超时 例如 我正在使用 gem 来联系 API 并且希望确保在我的应用程序和外部 API 之间存在连接问题时能够正确处理错误 我已经可以通过用录像机制作固定装置并从
  • 如何在 Rails 控制器中调用通道方法?

    我有一个订阅用户的 ActionCable 方法 如果启动新的 convo 我也希望用户订阅新频道 我无法找出在控制器中调用通道方法的正确语法 更新 问题是消息在发送时附加到聊天框 但是当发送第一条消息时 Websocket 连接尚未建立
  • Rails 注释分段错误

    有一些问题围绕着这个问题 但没有什么真正能满足我的需求 After I bundle install下面列出了我的 Gemfile 我运行annotate并出现以下错误 Users nickcoelius rvm gems ruby 1 8
  • 可以覆盖/实现的 ruby​​ 运算符列表

    是否有可以覆盖的所有 ruby 运算符的列表 不是那些不能的 Here s Ruby 运算符表 http phrogz net programmingruby language html table 18 4 方法和可重载的有 Elemen
  • 预期的 ProductField,出现数组问题

    我有一个 Rails 4 应用程序 它有一个如下所示的 params 块 def store params params require store permit name description user id products attr
  • 如何向 Time.now 添加两周?

    如何在 Ruby 中向当前 Time now 添加两周 我有一个使用 DataMapper 的小型 Sinatra 项目 在保存之前 我有一个字段填充了当前时间加上两周 但未按需要工作 任何帮助是极大的赞赏 我收到以下错误 NoMethod
  • 创建一个简单的 Rails 3 文本助手 Gem [重复]

    这个问题在这里已经有答案了 我一直在开发我的第一个 Rails 3 插件 以打包一个我喜欢在ApplicationHelper我所有的应用程序 你可以看到整个代码在 Github 上 https github com burlesona s
  • 如何从 Ruby 程序发送邮件?

    我想从 Ruby 应用程序发送电子邮件 核心语言中是否有调用来执行此操作 或者是否有我应该使用的库 最好的方法是什么 如果你不想使用行动邮递员 http wiki rubyonrails org rails pages ActionMail
  • 使用 VCR 过滤敏感数据

    我正在使用 VCR gem 记录 http 交互并在将来重播它们 我想过滤掉 uri 请求中的实际密码值 以下是 uri 的示例 http services somesite com Services asmx Cabins Usernam
  • Rails/Nginx 中的超时——最佳实践

    我正在开发一个应该在 Nginx 服务器上运行的 Rails 应用程序 根据输入 应用程序可能需要很长时间来处理请求 或者在出现错误时挂起 因此我想防止进程永远运行 除了确保客户端收到超时信号的 Nginx 配置之外 我想我可能仍然需要确保
  • Rails - 渲染:目标锚标记的操作?

    我希望像这样使用渲染 render action gt page form 我也尝试过这个 render template gt site page form 那也没用 这个特定页面上的表单位于最底部 如果提交时发生任何错误 我不希望用户被
  • rvm gem 安装错误?

    我正在摆弄 ruby gems 和 rvm 它工作得很好 但现在当我尝试安装 gem 时出现错误 gem install Rails错误 同时 执行 gem Errno EACCES 权限被拒绝 Users da rvm gems ruby
  • Windows 7 x64 上的 Ruby on Rails SQLite 问题

    当我尝试做的时候db create使用 Windows 7 x64 在具有此数据库配置的 sqlite 数据库上 development adapter sqlite3 database db development sqlite3 tim
  • Bundle 说 gem 丢失了 - 但事实并非如此?

    背景 我正在维护contentRuby On Rails 站点 但我确实没有 Rails 的经验 当尝试运行 Rails 服务器时 rails s我明白了 在任何来源中均找不到 activesupport 3 2 0 Run bundle
  • 红宝石接球和效率

    catch在 Ruby 中意味着跳出深度嵌套的代码 在 Java 中 例如用Java也可以达到同样的效果try catch用于处理异常 但它被认为是糟糕的解决方案 而且效率非常低 在 Ruby 中 我们有处理异常的方法begin raise
  • Ruby 是否有一个 Expect 等效 gem?

    Ruby 是否有一个 Expect 等效 gem 我尝试在 code google 和 ruby gems org 上搜索 但遗憾的是它没有出现 FYI Expect http en wikipedia org wiki Expect是一个
  • 使用哈希参数进行 DRY Ruby 初始化

    我发现自己经常在构造函数中使用哈希参数 尤其是在为配置或最终用户将接触到的其他 API 编写 DSL 时 我最终做的是类似以下的事情 class Example PROPERTIES name age PROPERTIES each p a
  • 什么是适合 Rails 3 的测试框架?

    去年我一直在使用 Ruby On Rails 但是 无法进行单元测试 现在我必须编写单元测试代码 哪个测试框架好 为什么 有这方面的好的教程吗 我的系统配置 Ruby 1 9 2 Rails 3 Ubuntu 10 第一个技巧是 尝试升级到
  • 超类与类SpecificationPolicy不匹配

    我得到了一个superclass mismatch for class SpecificationPolicy尝试安装或升级某些brew 软件包时出错 例如 更新安装 supabase CLI 时 brew install supabase
  • 使用 ruby​​ 调整动画 GIF 图像的大小?

    我正在尝试将 GIF 图像调整为不同的尺寸 我在 ruby 中使用 RMagick 库 但对于某些 gif 图像 即使我缩小 GIF 的大小 文件大小似乎也会增加 我正在以相同的纵横比调整图像图像的大小 这是我的代码 require rma

随机推荐

  • 与 Python 中的另一个命令行程序交互

    我需要编写一个 Python 脚本 它可以运行另一个命令行程序并与其标准输入和标准输出流交互 本质上 Python 脚本将从目标命令行程序中读取数据 通过写入其 stdin 进行智能响应 然后再次从程序中读取结果 它会重复执行此操作 我查看
  • Microsoft 认知 API 的正确密钥

    我目前正在尝试在 MS 认知服务 Bing 搜索 API 上进行新闻搜索 我读过很多文档 但似乎被困住了 这是我正在使用的代码 url https bingapis azure api net api v5 news search q mi
  • C++ 进程管理 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否有一个众所周知的 可移植的 好的 C 进程管理库 我发现了一个很有前途的图书馆叫做升压过程 htt
  • Java Keystore 是否存在性能问题? [复制]

    这个问题在这里已经有答案了 我们开发了一个应用程序来加密 解密来自服务器的请求 响应 我们正在做性能测试 加密 解密应用程序 我们观察到加密 解密过程需要时间 而许多线程 正在同时做 为了识别问题 我们记录了加密 解密过程中的所有方法 从记
  • ERRO[0001] 等待容器时出错:上下文已取消

    运行 docker 镜像时出现错误 看起来问题出在我的电脑上 我使用的是 MacOS 10 13 6 我已按照步骤创建 docker 映像 Sanjeet server api sanjeet docker build t apiconta
  • 删除 ggplot 地图/choropleth 中的边框线

    我想删除 ggplot 中生成的等值线区域之间的线 我的问题是由一张非常大的地图引起的 其中包含非常非常小的区域 人口普查区块组 这些区域数量如此之多 以至于鉴于边界的密度 不可能看到填充形状的颜色 我在 Mac 上使用更新后的 RStud
  • “isset构造”有捷径吗?

    我经常写这行代码 myParam isset params myParam params myParam defaultValue 通常 它会使嵌套数组的行变得很长 我可以把它改短一点吗 function getOr var default
  • ZeroMQ在多线程应用程序中处理中断

    多线程环境下ZeroMQ的优雅退出 规格 带有 c 11 的 ubuntu 16 04 libzmq 4 2 3 示例代码 static int s interrupted 0 static void s signal handler in
  • 从 Google Build 部署 Google Cloud 功能

    当尝试部署一个简单的功能时 我遇到了 403 错误 这是我的完整 yaml steps Install Dependencies name python id Pip install args pip3 install r requirem
  • 如何确定使用哪个框架来构建特定的 Windows 桌面应用程序?

    如何确定使用哪个平台或编程语言来构建特定的 Windows 桌面应用程序 有多种方法可以尝试检测特定软件是用哪种语言编写的 通常 执行检查的工具PE标头 http en wikipedia org wiki Portable Executa
  • 如何在 awk 或 sed 中编写查找所有函数(使用正则表达式)

    我有运行 python 的 bash 函数 它从标准输入返回所有找到的正则表达式 function find all python c import re import sys print n join re findall 1 sys s
  • 为什么使用牛顿法的 FindMaximum 会抱怨找不到足够的函数减少?

    首先 这看起来 来自 ContourPlot 是一个相当简单的最大化问题 为什么使用牛顿法的 FindMaximum 会出现问题 其次 如何摆脱警告 第三 如果我无法摆脱这些警告 我如何判断警告是否有意义 即最大化失败 例如 在下面的代码中
  • “System.Composition.TypedParts.dll”在哪里?

    我正在尝试使用容器配置来自托管扩展性框架 MEF 的类型 根据here http msdn microsoft com en us library system composition hosting containerconfigurat
  • 尝试将 nil 与数字堆栈回溯进行比较?

    我正在通过以下链接玩 Lua https www lua org pil 4 2 html https www lua org pil 4 2 html并对某一点感到困惑 Lua 5 2 4 Copyright C 1994 2015 Lu
  • 我在统一复制门时遇到问题

    我正在尝试统一复制我的门 但是 当我尝试这样做时 只有原来的门正在执行打开和关闭等动画 我有一个 UI 按钮 它使用 OnClick 函数来操作门 当我输入触发器时它会弹出 这是带有OnClick功能的按钮UI https i stack
  • iReport:如何隐藏带有文本字段的行,而没有数据行包含不同类型的数据

    我有空文本字段 它包含字符串或大十进制值 放在为我的报告拉出的单行上 该行显示一个空行 为了删除具有空行的空白行 我使用了该属性isRemoveLineWhenBlank对于该行中的报表元素 但这是行不通的 有人可以帮我解决这个问题吗 sn
  • usort 不适用于 laravel 多维数组

    我有一个数组 Illuminate Support Collection Object items protected gt Array 0 gt stdClass Object id gt 79 name gt shelin status
  • 我可以实施对半取偶吗?

    我需要去做四舍五入到偶数 https en wikipedia org wiki Rounding Round half to even在浮子上 即 如果该值是两个整数之间的中间值 打破平局 y 的小数部分正好是 0 5 则四舍五入到最接近
  • 如何在 Android 4.1+ 上将自签名 SSL 证书导入到 Volley

    我开发的android应用程序使用Volley 所有通信均通过HTTPS联系 因为我是在本地环境测试的 所以我对Tomcat使用自签名证书 之前我只有安卓2 3 and 3 0设备 现在我也有了4 1和4 4 我的实现使用这种方法 http
  • 如果 gem 安装不支持,本机扩展会回退到纯 Ruby

    我正在开发一个 gem 目前是纯 Ruby 但我也一直在为其中一个功能开发更快的 C 变体 该功能在纯 Ruby 中可用 但有时很慢 这种缓慢只会影响一些潜在用户 取决于他们需要哪些功能 以及他们如何使用这些功能 因此 如果 gem 无法在