今回は拡張ライブラリを含むGemを開発するための流れを学習するために、簡単なgemをつくることにします。
簡単なC言語で記述された拡張をGemで配布できる最低限の状態まで構築します。
Gemの雛形を生成する。
$ bundle gem ext_example
create ext_example/Gemfile
create ext_example/Rakefile
create ext_example/LICENSE.txt
create ext_example/README.md
create ext_example/.gitignore
create ext_example/ext_example.gemspec
create ext_example/lib/ext_example.rb
create ext_example/lib/ext_example/version.rb
Initializing git repo in /Users/hirocaster/src/github.com/hirocaster/ext_example
rake-compiler を導入する
ext_example.gemspec
を記述する
spec.summary
とspec.description
は適当に記述する。
spec.extensions
には後程つくるファイルを記述しておく。
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
spec.version = ExtExample::VERSION
spec.authors = ["hirocaster"]
spec.email = ["[email protected]"]
- spec.summary = %q{TODO: Write a short summary. Required.}
- spec.description = %q{TODO: Write a longer description. Optional.}
+ spec.summary = %q{C extensions example}
+ spec.description = %q{C extensions example}
spec.homepage = ""
spec.license = "MIT"
@@ -18,6 +18,9 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
+ spec.extensions = %w{ext/ext_example/extconf.rb}
+
spec.add_development_dependency "bundler", "~> 1.5"
spec.add_development_dependency "rake"
+ spec.add_development_dependency "rake-compiler"
end
bundle installを実行してrake-compilerを導入する。
$ bundle install
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Using bundler (1.5.3)
Using ext_example (0.0.1) from source at .
Installing rake (11.2.2)
Installing rake-compiler (0.9.9)
Your bundle is complete!
Gems in the group production were not installed.
I was installed into ./vendor/bundle
rake-compilerを稼動させる環境をつくる
拡張ライブラリはextディレクトリ以下に記述していく。
$ mkdir -p ext/ext_example/
$ touch ext/ext_example/extconf.rb
extconf.rb にはMakfileを作成するおまじないを記述。
require 'mkmf'
create_makefile('ext_example/ext_example')
Rakefile
に先程のextconf.rbを利用してTaskを定義できるように記述
require "rake/extensiontask"
Rake::ExtensionTask.new("ext_example") do |ext|
ext.lib_dir = "lib/ext_example"
end
これでC言語で記述したライブラリをコンパイルするためのTaskが定義されるはずなので、確認する。
$ rake -T
rake build # Build ext_example-0.0.1.gem into the pkg directory
rake clean # Remove any temporary products
rake clobber # Remove any generated files
rake compile # Compile all the extensions
rake compile:ext_example # Compile ext_example
rake install # Build and install ext_example-0.0.1.gem into system gems
rake release # Create tag v0.0.1 and build and push ext_example-0.0.1.gem to Rubygems
ここまでの準備でrake compile:ext_example
などのタスクが表示されるのを確認できる。
拡張ライブラリを書く
拡張ライブラリの中心となるext/ext_example/ext_example.c
を記述する。
Rubyは拡張ライブラリをロードする時に「Init_ライブラリ名」と いう関数を自動的に実行します.
https://github.com/ruby/ruby/blob/trunk/doc/extension.ja.rdoc#cコードを書く
ということなのでInit_ext_example()
を定義。
#include <stdio.h>
void Init_ext_example()
{
puts("Hello World!");
}
この拡張をロードするようにlib/ext_example.rb
に記述する。
@@ -1,4 +1,5 @@
require "ext_example/version"
+require "ext_example/ext_example"
module ExtExample
# Your code goes here...
コンパイルする。
$ rake compile:ext_example
mkdir -p tmp/universal.x86_64-darwin14/ext_example/2.0.0
cd tmp/universal.x86_64-darwin14/ext_example/2.0.0
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby -I. ../../../../ext/ext_example/extconf.rb
creating Makefile
cd -
cd tmp/universal.x86_64-darwin14/ext_example/2.0.0
/usr/bin/make
compiling ../../../../ext/ext_example/ext_example.c
linking shared-object ext_example/ext_example.bundle
cd -
mkdir -p tmp/universal.x86_64-darwin14/stage/lib/ext_example
install -c tmp/universal.x86_64-darwin14/ext_example/2.0.0/ext_example.bundle lib/ext_example/ext_example.bundle
cp tmp/universal.x86_64-darwin14/ext_example/2.0.0/ext_example.bundle tmp/universal.x86_64-darwin14/stage/lib/ext_example/ext_example.bundle
実際に動作させてみる。
$ irb
irb(main):001:0> require "ext_example"
Hello World!
=> true
irb(main):002:0>
Hello World!
が出力されたので、無事に動作することが確認でききました。
ここまででC言語で記述した拡張を含む、最低限のGemを作成することができました。
拡張ライブラリの処理を実用的にしていくためには
Rubyの拡張ライブラリを開発するためのドキュメント が日本語であります。こちらを参考にしていくと、やりたいことをC言語でどのように記述してRubyと連携をとっていけばいいのか理解できるようになると思います。