C extensions easy in Ruby                                       Apr 17th 2012                                       Muriel...
Why Ruby and C ?
Ruby without C
C without Ruby
Ruby and C combined
Ruby and C are                   already coupledRuby core: around 100 classes written in C (String, Rational, Marshal, IO....
Now You can write yourown C extensions easily
What is a C extension ?A requirable library from Ruby code ... require myext… that can use any other Rubys object or libra...
Technically speakingA C extension is a compiled library (.so or .dll) that:defines 1 specific C function,is accessible in ...
What do you need to             write C extensions ?A C development environment ([g]cc, ld, [g]make...)  Already installed...
How to write your C    extension
Default Ruby program            structuremyapp/  bin/    exec.rb  lib/    myapp/       mylib.rb  ext/    myapp/       myex...
Write the C file               ext/myapp/myext.c#include "ruby.h"void Init_myext() {    printf("Hello Ruby from C!n");}
Write the extconf file              ext/myapp/extconf.rbrequire mkmfcreate_makefile(myext)And thats it!Your C extension is...
How to compile and use  your C extension
Compile it                              in ext/myapp/=> ruby extconf.rbcreating Makefile          => ext/myapp/Makefile=> ...
Use it                               bin/exec.rb#!/bin/env rubyputs Before requiring C extensionrequire myapp/myextputs Af...
And now, package it in a    nice Ruby gem!
First flavor:          Package the compiled                      extensionAdd the compiled extension to the files list (li...
Platform dependent:                              gem spec                      myapp.compiled.gemspec.rbGem::Specification...
Platform dependent:                 Install and run it=> gem install my_app_compiled-0.1-x86-  cygwin.gemSuccessfully inst...
Second flavor:          Platform independent                     packagingAdd the C extension source files to the files li...
Platform independent:                           gem spec                    myapp.gemspec.rbGem::Specification.new do |spe...
Platform independent:                Install and run it=> gem install my_app-0.1.gemBuilding native extensions. This could...
Which flavor the best ?Platform dependent:   Platform independent:Need to release 1     Need to release just 1 Ruby gem pe...
Need more than a Hello      World ?  => The Ruby C API
module MyModule                  class MyClass                    def my_method(param1, param2,                  param3)  ...
if param1 == nil                              puts Param1 is nil                              return nil                  ...
param2.each do |elem|                               elemstr = elem.to_s                               elemstr[0] = A      ...
param3.block_method(3) do |                          block_param|                          puts param1 + block_param      ...
Using external compiled       libraries      => FFI gem
FFI gem Import external functions from acompiled library into a Ruby module  require ffi  module MyLib    extend FFI::Libr...
FFI featuresIt has a very intuitive DSLIt supports all C native typesIt supports C structs (also nested),   enums and glob...
Links          Makefile generation options:          Linuxtopia tutorial          mkmf rdoc          Ruby C API:          ...
Q/A
Upcoming SlideShare
Loading in …5
×

Ruby C extensions at the Ruby drink-up of Sophia, April 2012

2,190 views

Published on

Presented at the Ruby Drink-up of Sophia Antipolis on the 17th of April 2012 by Muriel Salvan (@MurielSalvan).

Published in: Technology, Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
2,190
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Ruby C extensions at the Ruby drink-up of Sophia, April 2012

  1. 1. C extensions easy in Ruby Apr 17th 2012 Muriel Salvan Open Source Lead developer and architect X-Aeon Solutions http://x-aeon.com
  2. 2. Why Ruby and C ?
  3. 3. Ruby without C
  4. 4. C without Ruby
  5. 5. Ruby and C combined
  6. 6. Ruby and C are already coupledRuby core: around 100 classes written in C (String, Rational, Marshal, IO...)Ruby standard libs: 35 libs written in C: (BigDecimal, Date, OpenSSL...)
  7. 7. Now You can write yourown C extensions easily
  8. 8. What is a C extension ?A requirable library from Ruby code ... require myext… that can use any other Rubys object or library,… written in C,… and compiled.
  9. 9. Technically speakingA C extension is a compiled library (.so or .dll) that:defines 1 specific C function,is accessible in Rubys load path (same as other .rb files)It is used the same way Rubys libraries (.rb) are (packaging, search path, require...)
  10. 10. What do you need to write C extensions ?A C development environment ([g]cc, ld, [g]make...) Already installed on *nix Cygwin, MinGW, Ruby DevKit on WindowsLittle C knowledgeSome Rubys C API knowledge
  11. 11. How to write your C extension
  12. 12. Default Ruby program structuremyapp/ bin/ exec.rb lib/ myapp/ mylib.rb ext/ myapp/ myext.c extconf.rb myotherlib/ otherlib.c extconf.rb
  13. 13. Write the C file ext/myapp/myext.c#include "ruby.h"void Init_myext() { printf("Hello Ruby from C!n");}
  14. 14. Write the extconf file ext/myapp/extconf.rbrequire mkmfcreate_makefile(myext)And thats it!Your C extension is ready to be compiled and used
  15. 15. How to compile and use your C extension
  16. 16. Compile it in ext/myapp/=> ruby extconf.rbcreating Makefile => ext/myapp/Makefile=> makegcc -I. -I/usr/lib/ruby/1.8/i386-cygwin -I/usr/lib/ruby/1.8/i386-cygwin -I. -g -O2 -c myext.cgcc -shared -s -o myext.so myext.o -L. -L/usr/lib -L. -Wl,--enable-auto-image-base,--enable-auto-import,-- export-all -lruby -ldl -lcrypt => ext/myapp/myext.so
  17. 17. Use it bin/exec.rb#!/bin/env rubyputs Before requiring C extensionrequire myapp/myextputs After requiring C extension=> ruby -Iext bin/exec.rbBefore requiring C extensionHello Ruby from C!After requiring C extension
  18. 18. And now, package it in a nice Ruby gem!
  19. 19. First flavor: Package the compiled extensionAdd the compiled extension to the files list (like any other library)Add your ext/ directory as a required pathDont forget to set your Gem platform as specific!
  20. 20. Platform dependent: gem spec myapp.compiled.gemspec.rbGem::Specification.new do |spec| spec.name = my_app_compiled spec.version = 0.1 spec.summary = Summary spec.author = me spec.bindir = bin spec.executable = exec.rb spec.files = [ bin/exec.rb, ext/myapp/myext.so ] spec.platform = Gem::Platform::CURRENT spec.require_path = extend=> gem build myapp.compiled.gemspec.rb Successfully built RubyGem Name: my_app_compiled Version: 0.1 File: my_app_compiled-0.1-x86-cygwin.gem
  21. 21. Platform dependent: Install and run it=> gem install my_app_compiled-0.1-x86- cygwin.gemSuccessfully installed my_app_compiled-0.1- x86-cygwin1 gem installedInstalling ri documentation for my_app_compiled-0.1-x86-cygwin...Installing RDoc documentation for my_app_compiled-0.1-x86-cygwin...=> exec.rbBefore requiring C extensionHello Ruby from C!After requiring C extension
  22. 22. Second flavor: Platform independent packagingAdd the C extension source files to the files listAdd your ext/ directory as a required pathKeep your Gem platform as RubyRegister the C extension (path to the extconf.rb file)
  23. 23. Platform independent: gem spec myapp.gemspec.rbGem::Specification.new do |spec| spec.name = my_app # { ... } spec.executable = exec.rb spec.files = [ bin/exec.rb, ext/myapp/myext.c, ext/myapp/extconf.rb ] spec.platform = Gem::Platform::RUBY spec.require_path = ext spec.extensions = [ ext/myapp/extconf.rb ]end gem build myapp.gemspec.rb=> Successfully built RubyGem Name: my_app Version: 0.1 File: my_app-0.1.gem
  24. 24. Platform independent: Install and run it=> gem install my_app-0.1.gemBuilding native extensions. This could take a while...Successfully installed my_app-0.11 gem installedInstalling ri documentation for my_app-0.1...Installing RDoc documentation for my_app-0.1...=> exec.rbBefore requiring C extensionHello Ruby from C!After requiring C extension
  25. 25. Which flavor the best ?Platform dependent: Platform independent:Need to release 1 Need to release just 1 Ruby gem per Ruby gem platform (need to Users must have a C compile on each development platform) environment toUsers do not need install it any development environment
  26. 26. Need more than a Hello World ? => The Ruby C API
  27. 27. module MyModule class MyClass def my_method(param1, param2, param3) end end endstatic VALUE myclass_mymethod( VALUE rb_self, VALUE rb_param1, VALUE rb_param2, VALUE rb_param3) {}void Init_myext() { VALUE mymodule = rb_define_module("MyModule"); VALUE myclass = rb_define_class_under(mymodule, "MyClass", rb_cObject); rb_define_method(myclass, "my_method", myclass_mymethod, 3);}
  28. 28. if param1 == nil puts Param1 is nil return nil else return param1 + 42 endif (rb_param1 == Qnil) { rb_funcall(rb_self, rb_intern("puts"), 1, rb_str_new2("Param1 is nil")); return Qnil;} else { int param1 = FIX2INT(rb_param1); VALUE result = INT2FIX(param1 + 42); return result;}
  29. 29. param2.each do |elem| elemstr = elem.to_s elemstr[0] = A puts elemstr[0..3] endint nbrelems = RARRAY(rb_param2)->len;int idx;for (idx = 0; idx < nbrelems; ++idx) { VALUE rb_elem = rb_ary_entry(rb_param2, idx); VALUE rb_elemstr = rb_funcall(rb_elem, rb_intern("to_s"), 0); char* elemstr = RSTRING_PTR(rb_elemstr); elemstr[0] = A; char* substr = (char*)malloc(5); strncpy(substr, elemstr, 4); substr[4] = 0; rb_funcall(rb_self, rb_intern("puts"), 1, rb_str_new2(substr)); free(substr);}
  30. 30. param3.block_method(3) do | block_param| puts param1 + block_param endstatic VALUE call_block_method(VALUE rb_params) { VALUE rb_object = rb_ary_entry(rb_params, 0); VALUE rb_value = rb_ary_entry(rb_params, 1); return rb_funcall(rb_object, rb_intern("block_method"), 1, rb_value);}static VALUE yielded_block(VALUE rb_yield_params, VALUE rb_iterate_params) { VALUE rb_block_param = rb_yield_params; VALUE rb_self = rb_ary_entry(rb_iterate_params, 0); VALUE rb_param1 = rb_ary_entry(rb_iterate_params, 1); return rb_funcall(rb_self, rb_intern("puts"), 1, INT2FIX(FIX2INT(rb_block_param)+FIX2INT(rb_param1)));}rb_iterate( call_block_method, rb_ary_new3(2, rb_param3, INT2FIX(3)), yielded_block, rb_ary_new3(2, rb_self, rb_param1)); Thanks Matz for Ruby!
  31. 31. Using external compiled libraries => FFI gem
  32. 32. FFI gem Import external functions from acompiled library into a Ruby module require ffi module MyLib extend FFI::Library ffi_lib c attach_function :puts, [ :string ], :int end MyLib.puts Hello, World using libc!
  33. 33. FFI featuresIt has a very intuitive DSLIt supports all C native typesIt supports C structs (also nested), enums and global variablesIt supports callbacksIt has smart methods to handle memory management of pointers and structs
  34. 34. Links Makefile generation options: Linuxtopia tutorial mkmf rdoc Ruby C API: Eqqon article Matz Readme Metaprogramming FFI gemThis presentation is available under CC-BY license by Muriel Salvan
  35. 35. Q/A

×