【问题标题】:How do I make a gem that targets both MRI and JRuby?如何制作同时针对 MRI 和 JRuby 的 gem?
【发布时间】:2012-11-23 21:49:55
【问题描述】:

我想制作一个 gem,当其他人尝试将它与 MRI 一起使用时,它将使用 C 代码,而当他们从 JRuby 使用它时,它将使用 Java 代码。

nokogiri 和 puma gems 就是这样做的,我看过他们的代码,但没有看到他们是如何实现的。

【问题讨论】:

  • 我说的不是这个。我想制作一个 gem,当其他人尝试将它与 MRI 一起使用时,它将使用 C 代码,而当他们从 JRuby 使用它时,它将使用 Java 代码。 nokogiri 和 puma gems 这样做,我看过他们的代码,但没有看到他们是如何实现的
  • 最简单的方法是用 ruby​​ 编写 gem,这样你就可以在 jRubyMRI 或任何实现上运行它。它会运行良好。您尚未指定 gem 的外部依赖项。
  • 请回答我的问题,我问它是有原因的。用纯红宝石写作不是我想要做的。

标签: ruby gem jruby


【解决方案1】:

这是通过使用 rvm(或其他类似工具在 rubies 之间切换)和 rake-compiler 为您所针对的不同平台交叉编译 gem 来完成的。

gemspec 文件必须指定每个平台所需的文件;这是通过检查正在编译 gem 的平台来完成的:

Gem::Specification.new do |gem|
# . . .

  if RUBY_PLATFORM =~ /java/
    # package jars
    gem.files += ['lib/*.jar']
    # . . . 
  else
    # package C stuff
    gem.files += Dir['ext/**/*.c']
    # . . . 
    gem.extensions = Dir['ext/**/extconf.rb']
  end
end

Rakefile中,安装rake-compiler后,模式通常如下:

spec = Gem::Specification.load('hello_world.gemspec')

if RUBY_PLATFORM =~ /java/
  require 'rake/javaextensiontask'
  Rake::JavaExtensionTask.new('hello_world', spec)
else
  require 'rake/extensiontask'
  Rake::ExtensionTask.new('hello_world', spec)
end

但您可能需要针对不同平台执行特定任务。

使用 MRI,然后使用 rake native gem 进行编译;使用 JRuby,rake java gem——这就是像 rvm 这样的工具派上用场的地方。您最终会为您的 gem 获得不同的 gem 文件,每个平台一个,然后您可以将其作为 gem 发布。

请参阅 rake-compiler documentation 了解更多详情,或查看其他类似的项目,例如 redclothpg_array_parser(我发现它们是比 nokogiri 更好的例子)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    • 2015-10-17
    相关资源
    最近更新 更多