いちばんやさしいCでつくるgem

C言語でシンプルなgemを作ってみましょう。

まずはフォルダーを用意します。

my_c_gemが今回のgemの名前です。

my_c_gem/
└── ext
    └── my_c_gem
        ├── extconf.rb
        └── my_c_gem.c


こんな感じです。 extconf.rbにはMakefileを自動生成するためのコードを書きます。

extconf.rb

require "mkmf"
create_makefile "my_c_gem/my_c_gem"

my_c_gem.cには最初にrubyから呼ばれる初期化関数を書きます。まずは何もせずに MyCGemクラスを作るだけのコードをいれておきましょう。

my_c_gem.c

#include <ruby.h>

void
Init_my_c_gem(void) {

 rb_define_class("MyCGem",rb_cObject);

}

ではまずMakefileを生成してみましょう。

cd ext/my_c_gem ruby extconf.rb

Makefileができるのでコンパイルしてみましょう。makeを実行します。

すると my_c_gem.bundleというファイルが出来上がります。このファイルがルビーに組み込まれるライブラリーファイルです。

my_c_gem/
└── ext
    └── my_c_gem
        ├── Makefile
        ├── extconf.rb
        ├── my_c_gem.bundle
        ├── my_c_gem.c
        └── my_c_gem.o
        

ではこのbundleファイルを組み込んでrubyを実行してみましょう。

bundleファイルのあるフォルダーで

ruby -Ilib:. -r my_c_gem -e "p MyCGem.new”

と実行します。

#<mycgem:0x007f9d7b87b138>

こんな感じに出力されます。

ではここまでをRakefileにして自動化してしまいましょう。

require "rake/extensiontask"
Rake::ExtensionTask.new "my_c_gem" do |ext|
    ext.lib_dir = "lib/my_c_gem"
end

これでrake compileでlibフォルダーが出来その中にbundleファイルがコンパイルされるようになります。

my_c_gem/
├── Rakefile
└── ext
    └── my_c_gem
        ├── Makefile
        ├── extconf.rb
        └── my_c_gem.c

一度make cleanしてから rake compileをしてみましょう。

my_c_gem/
├── Rakefile
├── ext
│   └── my_c_gem
│       ├── Makefile
│       ├── extconf.rb
│       └── my_c_gem.c
├── lib
│   └── my_c_gem
│       └── my_c_gem.bundle
└── tmp
    └── universal.x86_64-darwin15
        ├── my_c_gem
        │   └── 2.0.0
        │       ├── Makefile
        │       ├── my_c_gem.bundle
        │       └── my_c_gem.o
        └── stage
            └── lib
                └── my_c_gem
                    └── my_c_gem.bundle

こんな感じでコンパイルが実行されます。

それではこれをbundle installできるようにしてみましょう。 まずはmy_c_gem.gemspecファイルをフォルダーのルートにつくります。

Gem::Specification.new do |spec|
  spec.name          = "my_c_gem"
  spec.version       = '1.0.0'
  spec.authors       = ["yamshing"]
  spec.email         = ["yamshing@..."]

  spec.summary       = %q{My first C gem}
  spec.description   = %q{This does nothing}
  spec.homepage      = ""
  spec.license       = "MIT"

  spec.files         = []
  spec.files         = %w[
  ext/my_c_gem/extconf.rb
  ext/my_c_gem/my_c_gem.c
  ]
  spec.require_paths = ["lib"]
  spec.extensions = %w[ext/my_c_gem/extconf.rb]

  spec.add_development_dependency "bundler", "~> 1.10"
  spec.add_development_dependency "rake", "~> 10.0"
  spec.add_development_dependency "minitest"
end

ここで大切なのはspec.filesに必要なファイルをリストするのとspec.extensionsにextconf.rbを入れるところです。

さらにRakefileの中にrequire "bundler/gem_tasks”をたしてrake buildコマンドが使えるようにしましょう。

Rakefile

require "bundler/gem_tasks"
require "rake/extensiontask"

Rake::ExtensionTask.new "my_c_gem" do |ext|

ext.lib_dir = "lib/my_c_gem"

end

いよいよ実行です。 rake build してみましょう。

問題がなければpkgフォルダーができその中にmy_c_gem-1.0.0.gemができているはずです。

これをインストールしてみましょう。

gem install -l pkg/my_c_gem-1.0.0.gem -V

コンパイルがはじまり1 gem installedがでれば成功です。

実行してみましょう。ただrequire してp するだけです。

ruby -e "require 'my_c_gem/my_c_gem'; p MyCGem.new"

#<MyCGem:0x007f9de99c8720>のような出力がでれば成功です。

なにもしないgemが完成しました。

コード

参考