我想制作一个 gem,当其他人尝试将它与 MRI 一起使用时,它将使用 C 代码,而当他们从 JRuby 使用它时,它将使用 Java 代码。
nokogiri 和 puma gems 做到了这一点,我浏览了他们的代码,但没有看到他们是如何实现的。
这是通过使用 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 文档,或查看执行相同操作的其他项目,例如redcloth或pg_array_parser(我发现它们是比 nokogiri 更好的示例)。