是什么让 gem 与 JRuby 不兼容?

What makes a gem incompatible with JRuby?

我 运行 bundle install 令我惊讶的是,大多数 Rails 4 附带的 gem 安装得很好。 byebug 没有,但没什么大不了的。

是什么让 gem 与 JRuby 完全不兼容?

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

可悲的是:据我所知,它只使用了public Ruby APIs,它实际上并没有使用YARV的任何私有内部信息VM,所以它也可以用便携式 Ruby.

编写

一般来说,gem 可能只适用于一种特定的 Ruby 实现有几个原因:

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

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