我正在开发一个宝石,这是一个纯
Ruby,但是我也为其中一个功能开发了一个更快的C变体.该功能在纯Ruby中可用,但有时较慢.缓慢只会影响一些潜在的用户(取决于他们需要哪些功能,以及它们如何使用它们),因此如果无法在目标系统上编译,则将宝石提供给仅限于Ruby的功能是有意义的.
我想在一个宝石中保留该功能的Ruby和C变体,并从安装的gem中提供最佳(即最快)的体验.这将使我能够从我的一个项目中支持最广泛的潜在用户.它还将允许其他人的依赖宝石和项目对目标系统使用最佳可用依赖关系,而不是兼容性的最低公分母版本.
我希望在运行时需要在主要的lib / foo.rb文件中出现,就像这样:
begin require 'foo/foo_extended' rescue LoadError require 'foo/ext_bits_as_pure_ruby' end
但是,我不知道如何让gem安装检查(或尝试和失败)本机扩展支持,以便gem可以正确安装,无论它是否可以构建“foo_extended”.当我研究如何做到这一点,我主要发现几年前的讨论,例如http://permalink.gmane.org/gmane.comp.lang.ruby.gems.devel/1479和http://rubyforge.org/pipermail/rubygems-developers/2007-November/003220.html意味着Ruby宝石并不真正支持此功能.没有什么最新的,所以我希望有一个人有一些更新的知识?
我的理想解决方案是在尝试构建扩展之前,检测到目标Ruby不支持(或者根本不想在项目级别)C本机扩展.但是,如果不是太脏,也可以尝试/捕捉机制.
这是可能的吗?或者是发布两个宝石变体的建议(例如foo和foo_ruby),当我搜索时,我找到了当前的最佳实践?
解决方法
这是一个想法,根据
http://guides.rubygems.org/c-extensions/和
http://yorickpeterse.com/articles/hacking-extconf-rb/的信息.
看来你可以将逻辑放在extconf.rb中.例如,查询RUBY_DESCRIPTION常量并确定您是否位于支持本机扩展的Ruby中:
$irb jruby-1.6.8 :001 > RUBY_DESCRIPTION => "jruby 1.6.8 (ruby-1.8.7-p357) (2012-09-18 1772b40) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_51) [darwin-x86_64-java]"
所以你可以尝试像在extconf.rb中的条件(在extconf.rb)中的代码:
unless RUBY_DESCRIPTION =~ /jruby/ do require 'mkmf' # stuff create_makefile('my_extension/my_extension') end
显然,您将需要更复杂的逻辑,抓取“宝石安装”等参数.