【问题标题】:What makes a gem incompatible with JRuby?是什么让 gem 与 JRuby 不兼容?
【发布时间】:2015-10-31 16:41:16
【问题描述】:

我运行了bundle install,令我惊讶的是,大多数随 Rails 4 一起提供的 gem 都安装得很好。 byebug 没有,但没什么大不了的。

究竟是什么让 gem 与 JRuby 不兼容?

【问题讨论】:

    标签: ruby gem bundler jruby


    【解决方案1】:

    在这种特殊情况下,gem 是作为 YARV 的 C 扩展编写的,因此它仅适用于 YARV,不适用于任何其他 Ruby 实现,包括但不限于 JRuby、Rubinius、MagLev、MRuby、IronRuby 等.

    可悲的是:据我所知,它只使用公共 Ruby API,实际上并没有使用 YARV VM 的任何私有内部信息,所以它也可以用可移植的 Ruby 编写。

    一般来说,一个 gem 可能只在一个特定的 Ruby 实现上工作有几个原因:

    • 它使用主机平台的某些特定功能,而并非所有 Ruby 实现都可以使用。例如,使用 Java 平台库的 Java 编写的 gem 很可能无法与 YARV 一起使用,而只能与 JRuby 一起使用。
    • 它访问特定 Ruby 实现的私有内部实现细节。这很明显,我想。 如此明显的是,即使在基于 C 的 Ruby 实现中也没有可移植的 C API。通常称为“Ruby C 扩展 API”的东西实际上只是 YARV 暴露其内部结构。 Rubinius 和 JRuby 都投入了大量工作为 YARV 开发仿真层,因此至少有一些 C 扩展可以工作,但这很难。例如:YARV 的垃圾收集器非常简单,它从不移动内存中的对象。许多 C 扩展都依赖于此,但对于现代 GC(如 Rubinius 或 JVM)来说,这根本不是真的。 YARV 不允许多个 Ruby 线程同时运行,许多 C 扩展依赖于此,但对于几乎所有其他 Ruby 实现来说,情况并非如此。等等……另外,那些仿真层很慢。真的很慢。 “为提高性能而用 C 语言重新编写”的 gem 完全有可能比 JRuby 或 Rubinius 上的纯 Ruby 对应物运行得慢。 (毕竟,在某些情况下,Rubinius 已经可以与 C 竞争。例如,Rubinius 中的 Hash 类是用 Ruby 编写的,其性能与 YARV 用 C 编写的 Hash 类相当。)
    • 它使用了特定实现中缺少的 Ruby 功能。例如,细化已被广泛批评为在执行方法查找的积极优化的实现中无法实现(或更准确地说:细化,它们当前指定的方式,使得无法应用这些优化)。 Refinements 的设计者碰巧都是 YARV 开发人员,这无关紧要,因为 YARV 无论如何都不会优化方法查找,但是例如JRuby 开发人员决定干脆不实现 Refinements。 (10 年前,他们对延续做了同样的事情。)所以,如果一个 gem 使用了 Refinements,它就不能在 JRuby 上工作。

    Rubinius 和 JRuby 开发人员开发了一个 FFI API,可用于使 C API 从 Ruby 中可用,这种方式可以在许多 Ruby 实现中移植。 Rubinius、JRuby、MacRuby 和(我相信)MagLev 原生支持 FFI,对于 YARV,有一个 gem 为其添加了 FFI 支持。使用独立于实现的 FFI API 而不是 YARV API 的 Gem 应该适用于几乎所有的实现。但是,FFI API 不提供对实现内部的访问权限(显然),因此对于某些 gem 来说它是不可用的。例如,有些 gem 试图让您访问 Proc 的源代码,这是高度特定于实现的(甚至可能不起作用,例如,当您提前编译为 Java .class 文件时使用jrubyc,源代码甚至在运行时都不存在),因此每个 Ruby 实现都必须有该 gem 的不同版本。

    【讨论】:

      猜你喜欢
      • 2013-07-14
      • 2017-12-04
      • 1970-01-01
      • 1970-01-01
      • 2013-10-21
      • 2017-10-08
      • 2014-11-06
      • 1970-01-01
      • 2014-08-16
      相关资源
      最近更新 更多