2012-11-23 52 views
6

我想創造一個寶石,當其他人試圖將它用於MRI時,它將使用C代碼,當他們從JRuby使用它時,它將使用Java代碼。我該如何製作既針對MRI又針對JRuby的寶石?

nokogiri和彪馬寶石這樣做,我瞥了一眼他們的代碼,但沒有看到他們如何實現它。

+0

另請參閱http://stackoverflow.com/questions/3642085/make-bundler-use-different-gems-for-different-platforms – knut

+0

這不是我說的。我想製作一個寶石,當其他人試圖將它用於MRI時,它將使用C代碼,當他們從JRuby使用它時,它將使用Java代碼。 nokogiri和puma寶石是這樣做的,我瀏覽了他們的代碼,但沒有看到它們是如何實現的。 – jshen

+0

最簡單的方法是用ruby編寫gem,這樣你就可以在'jRuby'上運行它了。 ,「MRI」或任何實現。它會運行良好。你沒有指定什麼是你的寶石的外部依賴。 – nikhil

回答

6

這是通過使用rvm(或其他類似工具在紅寶石之間切換)和rake-compiler交叉編譯針對不同平臺的gem來完成的。

gemspec文件必須指定每個平臺所需的文件;這是通過檢查該平臺上完成的寶石被編譯:

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這樣的工具得到方便。你最終會得到不同的寶石文件,每個平臺都有一個寶石文件,然後你可以發佈爲寶石。

查看rake-compiler documentation瞭解更多詳情,或查看相同的其他項目,如redclothpg_array_parser(我發現它們比nokogiri更好的例子)。