2017-12-14
http://www.zenspider.com/projects/rubyinline.html
chruby の手順で Windows Services for Linux (Windows 10 version 1709) & Ubuntu 16.04 に Ruby 2.4.2 を入れて、試そうとしている。
$ chruby 2.4.2 $ which ruby /opt/rubies/ruby-2.4.2/bin/ruby $ ruby -v ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-linux] $ gem install -E RubyInline Fetching: ZenTest-4.11.1.gem (100%) Successfully installed ZenTest-4.11.1 Fetching: RubyInline-3.12.4.gem (100%) Successfully installed RubyInline-3.12.4 Parsing documentation for ZenTest-4.11.1 Installing ri documentation for ZenTest-4.11.1 Parsing documentation for RubyInline-3.12.4 Installing ri documentation for RubyInline-3.12.4 Done installing documentation for ZenTest, RubyInline after 1 seconds 2 gems installed
# inline_sample.rb require "inline" class MyTest inline do |builder| builder.c " long factorial(int max) { int i=max, result=1; while (i >= 2) { result *= i--; } return result; }" end end t = MyTest.new() puts t.factorial(10)
$ ruby inline_sample.rb 3628800
いまだに動いている。なんと。
ということはあいかわらず。。
$ pushd ~/.ruby_inline/ruby-2.4.0 $ ls -1 Inline_MyTest_cb89593d1f9fe3ecdb2178215eee80ae.c Inline_MyTest_cb89593d1f9fe3ecdb2178215eee80ae.c.old Inline_MyTest_cb89593d1f9fe3ecdb2178215eee80ae.so $ cat Inline_MyTest_cb89593d1f9fe3ecdb2178215eee80ae.c #include "ruby.h" # line 5 "inline_sample.rb" static VALUE factorial(VALUE self, VALUE _max) { int max = FIX2INT(_max); int i=max, result=1; while (i >= 2) { result *= i--; } return LONG2NUM(result); } #ifdef __cplusplus extern "C" { #endif void Init_Inline_MyTest_cb89593d1f9fe3ecdb2178215eee80ae() { VALUE c = rb_cObject; c = rb_const_get(c, rb_intern("MyTest")); rb_define_method(c, "factorial", (VALUE(*)(ANYARGS))factorial, 1); } #ifdef __cplusplus } #endif $ popd
# https://github.com/seattlerb/rubyinline/blob/master/demo/hello.rb begin require 'rubygems' rescue LoadError end require 'inline' class Hello inline do |builder| builder.include "<stdio.h>" builder.c 'void hello() { puts("hello world"); }' end end Hello.new.hello
$ ruby hello.rb /home/nishimotz/.gem/ruby/2.4.2/gems/RubyInline-3.12.4/lib/inline.rb:610: warning: Insecure world writable dir /home/nishimotz/.gem/ruby/2.4.2/bin in PATH, mode 040777 hello world
これもほぼサンプルのまま
# inline_cpp_sample.rb require 'inline' class MyTest inline(:C) do |builder| builder.include '<iostream>' builder.add_compile_flags '-x c++', '-lstdc++' builder.c ' void hello(int i) { while (i-- > 0) { std::cout << "hello" << std::endl; } }' end end t = MyTest.new() puts t.hello(3)
$ ruby inline_cpp_sample.rb /home/nishimotz/.gem/ruby/2.4.2/gems/RubyInline-3.12.4/lib/inline.rb:610: warning: Insecure world writable dir /home/nishimotz/.gem/ruby/2.4.2/bin in PATH, mode 040777 cc1plus: warning: command line option ‘-Wimplicit-int’ is valid for C/ObjC but not for C++ cc1plus: warning: command line option ‘-Wdeclaration-after-statement’ is valid for C/ObjC but not for C++ cc1plus: warning: command line option ‘-Wimplicit-function-declaration’ is valid for C/ObjC but not for C++ cc1plus: warning: unrecognized command line option ‘-Wno-self-assign’ cc1plus: warning: unrecognized command line option ‘-Wno-constant-logical-operand’ cc1plus: warning: unrecognized command line option ‘-Wno-parentheses-equality’ cc1plus: warning: unrecognized command line option ‘-Wno-tautological-compare’ /opt/rubies/ruby-2.4.2/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require': /home/nishimotz/.ruby_inline/ruby-2.4.0/Inline_MyTest_5d41402abc4b2a76b9719d911017c592.so: undefined symbol: _ZSt4cout - /home/nishimotz/.ruby_inline/ruby-2.4.0/Inline_MyTest_5d41402abc4b2a76b9719d911017c592.so (LoadError) from /opt/rubies/ruby-2.4.2/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require' from /home/nishimotz/.gem/ruby/2.4.2/gems/RubyInline-3.12.4/lib/inline.rb:523:in `load' from /home/nishimotz/.gem/ruby/2.4.2/gems/RubyInline-3.12.4/lib/inline.rb:857:in `inline' from inline_cpp_sample.rb:3:in `<class:MyTest>' from inline_cpp_sample.rb:2:in `<main>'
おっとエラーになった。
$ nm ~/.ruby_inline/ruby-2.4.0/Inline_MyTest_5d41402abc4b2a76b9719d911017c592.so |grep cout U _ZSt4cout
cout が so の中にないようだ。。
これは動いた:
# inline_cpp_sample2.rb require 'inline' class MyTest inline(:C) do |builder| builder.include '<complex>' builder.add_compile_flags '-x c++', '-lstdc++ -lm' builder.c ' double hello(double re, double im) { std::complex<double> c(re, im); double a = std::abs(c); return a; }' end end t = MyTest.new() puts t.hello(3, 5)
$ ruby inline_cpp_sample2.rb /home/nishimotz/.gem/ruby/2.4.2/gems/RubyInline-3.12.4/lib/inline.rb:610: warning: Insecure world writable dir /home/nishimotz/.gem/ruby/2.4.2/bin in PATH, mode 040777 cc1plus: warning: command line option ‘-Wimplicit-int’ is valid for C/ObjC but not for C++ cc1plus: warning: command line option ‘-Wdeclaration-after-statement’ is valid for C/ObjC but not for C++ cc1plus: warning: command line option ‘-Wimplicit-function-declaration’ is valid for C/ObjC but not for C++ cc1plus: warning: unrecognized command line option ‘-Wno-self-assign’ cc1plus: warning: unrecognized command line option ‘-Wno-constant-logical-operand’ cc1plus: warning: unrecognized command line option ‘-Wno-parentheses-equality’ cc1plus: warning: unrecognized command line option ‘-Wno-tautological-compare’ 5.830951894845301
うごいた
# inline_cpp_sample3.rb require 'inline' class MyTest inline(:C) do |builder| builder.include '<complex>' builder.add_compile_flags '-x c++', '-lstdc++ -lm', '-std=c++11' builder.c ' double hello(double re, double im) { std::complex<double> c(re, im); auto a = std::abs(c); return a; }' end end t = MyTest.new() puts t.hello(3, 5)
$ ruby inline_cpp_sample3.rb /home/nishimotz/.gem/ruby/2.4.2/gems/RubyInline-3.12.4/lib/inline.rb:610: warning: Insecure world writable dir /home/nishimotz/.gem/ruby/2.4.2/bin in PATH, mode 040777 cc1plus: warning: command line option ‘-Wimplicit-int’ is valid for C/ObjC but not for C++ cc1plus: warning: command line option ‘-Wdeclaration-after-statement’ is valid for C/ObjC but not for C++ cc1plus: warning: command line option ‘-Wimplicit-function-declaration’ is valid for C/ObjC but not for C++ cc1plus: warning: unrecognized command line option ‘-Wno-self-assign’ cc1plus: warning: unrecognized command line option ‘-Wno-constant-logical-operand’ cc1plus: warning: unrecognized command line option ‘-Wno-parentheses-equality’ cc1plus: warning: unrecognized command line option ‘-Wno-tautological-compare’ 5.830951894845301
http://rubyinline.rubyforge.org/RubyInline/
$ sudo gem install RubyInline [sudo] password for nishi: Successfully installed ZenTest-4.1.3 Successfully installed RubyInline-3.8.2 2 gems installed Installing ri documentation for ZenTest-4.1.3... Installing ri documentation for RubyInline-3.8.2... Installing RDoc documentation for ZenTest-4.1.3... Installing RDoc documentation for RubyInline-3.8.2...
http://blog.tkmr.org/tatsuya/show/299-ruby-c-rubyinline
に書かれているサンプルを実行するが、
inline_sample.rb:32: undefined method `plus_inline' for #<Test:0xb7bcf428> (NoMethodError)
になる。
気を取り直して gems に入っている example を実行したら動いた!
$ cp /usr/lib/ruby/gems/1.8/gems/RubyInline-3.8.2/example.rb . $ ruby example.rb # of iterations = 1000000, n = 5 user system total real null_time 1.310000 0.920000 2.230000 ( 2.621937) c 5.040000 2.790000 7.830000 ( 10.498556) c-raw 5.240000 2.560000 7.800000 ( 8.104351) c-alias 5.100000 2.700000 7.800000 ( 8.025086) pure ruby 20.700000 12.360000 33.060000 ( 35.544498)
関数名によって動かなくなるらしい。
動かない場合:
#!/usr/bin/ruby require 'rubygems' require 'inline' class Test inline do |builder| builder.c " int plus_inline(int x, int y){ return x + y; } " end end p Test.new.plus_inline(1,1)
$ ruby inline_sample.rb inline_sample.rb:13: undefined method `plus_inline' for #<Test:0xb7b9f124> (NoMethodError)
動く場合
#!/usr/bin/ruby require 'rubygems' require 'inline' class Test inline do |builder| builder.c " int add(int x, int y){ return x + y; } " end end p Test.new.add(1,1)
$ ruby inline_sample.rb 2
-d オプション付きで実行するといろいろ警告が出ているが、これでいいらしい。
$ ruby -d inline_sample.rb Exception `LoadError' at /usr/local/lib/site_ruby/1.8/rubygems.rb:1113 - no such file to load -- rubygems/defaults/operating_system Exception `NoMethodError' at /usr/lib/ruby/1.8/rational.rb:78 - undefined method `gcd' for Rational(1, 2):Rational Exception `LoadError' at /usr/local/lib/site_ruby/1.8/rubygems/config_file.rb:34 - no such file to load -- Win32API Exception `LoadError' at /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31 - no such file to load -- inline RubyInline v 3.8.2 Exception `LoadError' at /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31 - no such file to load -- inline/Inline_Test_34ec.so Exception `LoadError' at /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:38 - no such file to load -- inline/Inline_Test_34ec.so /home/nishi/.ruby_inline/Inline_Test_34ec.so is up to date 2
ちゃんとherokuで使えるということがわかった。
$ ./script/generate scaffold item name:string $ echo "RubyInline" >> .gems
items_controller.rb
require 'inline' class Test inline do |builder| builder.c " int add(int x, int y) { return x + y; } " end end class ItemsController < ApplicationController # GET /items # GET /items.xml def index @items = Item.all @test = Test.new.add(1, 1) 以下略
items/index.html.erb
<h1>Listing items</h1> <p> test = <%= @test %> </p> 以下略
のようなものが git push heroku master; heroku db:migrate して http://app-name.heroku.com/items/ で動いた。