SlideShare a Scribd company logo
C extensions easy in Ruby




                                       Apr 17th 2012
                                       Muriel Salvan
                  Open Source Lead developer and architect
                                       X-Aeon Solutions
                                         http://x-aeon.com
Why Ruby and C ?
Ruby without C
C without Ruby
Ruby and C combined
Ruby and C are
                   already coupled
Ruby core: around 100 classes written in
 C (String, Rational, Marshal, IO...)
Ruby standard libs: 35 libs written in C:
 (BigDecimal, Date, OpenSSL...)
Now You can write your
own C extensions easily
What is a C extension ?


A requirable library from Ruby code ...
 require 'myext'

… that can use any other Ruby's object
 or library,
… written in C,
… and compiled.
Technically speaking


A C extension is a compiled library (.so
 or .dll) that:
defines 1 specific C function,
is accessible in Ruby's load path (same
  as other .rb files)
It is used the same way Ruby's libraries
   (.rb) are (packaging, search path,
   require...)
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 Windows
Little C knowledge
Some Ruby's C API knowledge
How to write your C
    extension
Default Ruby program
            structure
myapp/
  bin/
    exec.rb
  lib/
    myapp/
       mylib.rb
  ext/
    myapp/
       myext.c
       extconf.rb
       myotherlib/
         otherlib.c
         extconf.rb
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.rb


require 'mkmf'
create_makefile('myext')


And that's it!
Your C extension is ready to be compiled
 and used
How to compile and use
  your C extension
Compile it
                              in ext/myapp/
=> ruby extconf.rb
creating Makefile

          => ext/myapp/Makefile
=> make
gcc -I. -I/usr/lib/ruby/1.8/i386-cygwin
  -I/usr/lib/ruby/1.8/i386-cygwin -I.   -g -O2    -c
  myext.c
gcc -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
Use it
                               bin/exec.rb
#!/bin/env ruby
puts 'Before requiring C extension'
require 'myapp/myext'
puts 'After requiring C extension'

=> ruby -Iext bin/exec.rb
Before requiring C extension
Hello Ruby from C!
After requiring C extension
And now, package it in a
    nice Ruby gem!
First flavor:
          Package the compiled
                      extension
Add the compiled extension to the files
 list (like any other library)
Add your ext/ directory as a required
 path
Don't forget to set your Gem platform as
 specific!
Platform dependent:
                              gem spec
                      myapp.compiled.gemspec.rb
Gem::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 = 'ext'
end
=> 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
Platform dependent:
                 Install and run it
=> gem install my_app_compiled-0.1-x86-
  cygwin.gem
Successfully installed my_app_compiled-0.1-
  x86-cygwin
1 gem installed
Installing ri documentation for
  my_app_compiled-0.1-x86-cygwin...
Installing RDoc documentation for
  my_app_compiled-0.1-x86-cygwin...

=> exec.rb
Before requiring C extension
Hello Ruby from C!
After requiring C extension
Second flavor:
          Platform independent
                     packaging
Add the C extension source files to the
 files list
Add your ext/ directory as a required
 path
Keep your Gem platform as Ruby
Register the C extension (path to the
 extconf.rb file)
Platform independent:
                           gem spec
                    myapp.gemspec.rb
Gem::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
Platform independent:
                Install and run it
=> gem install my_app-0.1.gem
Building native extensions. This could take
  a while...
Successfully installed my_app-0.1
1 gem installed
Installing ri documentation for my_app-0.1...
Installing RDoc documentation for
  my_app-0.1...

=> exec.rb
Before requiring C extension
Hello Ruby from C!
After requiring C extension
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 to
Users do not need      install it
 any development
 environment
Need more than a Hello
      World ?
  => The Ruby C API
module MyModule
                  class MyClass
                    def my_method(param1, param2,
                  param3)
                    end
                  end
                end

static 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);
}
if param1 == nil
                              puts 'Param1 is nil'
                              return nil
                            else
                              return param1 + 42
                            end




if (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;
}
param2.each do |elem|
                               elemstr = elem.to_s
                               elemstr[0] = 'A'
                               puts elemstr[0..3]
                             end



int 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);
}
param3.block_method(3) do |
                          block_param|
                          puts param1 + block_param
                        end


static 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!
Using external compiled
       libraries
      => FFI gem
FFI gem

 Import external functions from a
compiled 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!'
FFI features

It has a very intuitive DSL
It supports all C native types
It supports C structs (also nested),
   enums and global variables
It supports callbacks
It has smart methods to handle memory
   management of pointers and structs
Links

          Makefile generation options:
          Linuxtopia tutorial
          mkmf rdoc
          Ruby C API:
          Eqqon article
          Matz' Readme
          Metaprogramming
          FFI gem

This presentation is available under CC-BY license by Muriel Salvan
Q/A

More Related Content

PDF
Introduction to web programming with JavaScript
PPTX
AngularJS Directives
PDF
Bca sem 6 php practicals 1to12
PPTX
Full stack devlopment using django main ppt
PPT
PDF
Introdução ao JavaScript
PPT
Introduction to java beans
Introduction to web programming with JavaScript
AngularJS Directives
Bca sem 6 php practicals 1to12
Full stack devlopment using django main ppt
Introdução ao JavaScript
Introduction to java beans

What's hot (20)

PPT
Js ppt
PPTX
Jenkins multibranch pipeline workshop sep 2018
PPTX
Basics of Object Oriented Programming in Python
PPT
Applet Architecture - Introducing Java Applets
PPT
RichControl in Asp.net
PPT
Advanced Web Development
PPT
Java Arrays
PDF
Java programming lab manual
DOCX
Lab manual asp.net
PDF
JavaScript - Chapter 8 - Objects
PDF
JAVASCRIPT PROGRAM.pdf
PPTX
Array,lists and hashes in perl
PPTX
ReactJS presentation.pptx
PDF
The Best (and Worst) of Django
PPT
PHP - DataType,Variable,Constant,Operators,Array,Include and require
PPT
Php with MYSQL Database
PPTX
Programming in Java
ODT
Testing in-python-and-pytest-framework
PPTX
Java Server Pages(jsp)
PPTX
Inheritance in java
Js ppt
Jenkins multibranch pipeline workshop sep 2018
Basics of Object Oriented Programming in Python
Applet Architecture - Introducing Java Applets
RichControl in Asp.net
Advanced Web Development
Java Arrays
Java programming lab manual
Lab manual asp.net
JavaScript - Chapter 8 - Objects
JAVASCRIPT PROGRAM.pdf
Array,lists and hashes in perl
ReactJS presentation.pptx
The Best (and Worst) of Django
PHP - DataType,Variable,Constant,Operators,Array,Include and require
Php with MYSQL Database
Programming in Java
Testing in-python-and-pytest-framework
Java Server Pages(jsp)
Inheritance in java
Ad

Viewers also liked (10)

ODP
Ruby and Docker on Rails
PDF
Pry at the Ruby Drink-up of Sophia, February 2012
PDF
Ruby 2.0 at the Ruby drink-up of Sophia, February 2013
PDF
Ruby and Twitter at the Ruby drink-up of Sophia, January 2013
PDF
Ruby object model at the Ruby drink-up of Sophia, January 2013
ODP
Piloting processes through std IO at the Ruby Drink-up of Sophia, January 2012
ODP
DRb at the Ruby Drink-up of Sophia, December 2011
ODP
Untitled talk at Riviera.rb
PDF
Quines—Programming your way back to where you were
ODP
The Dark Side of Programming Languages
Ruby and Docker on Rails
Pry at the Ruby Drink-up of Sophia, February 2012
Ruby 2.0 at the Ruby drink-up of Sophia, February 2013
Ruby and Twitter at the Ruby drink-up of Sophia, January 2013
Ruby object model at the Ruby drink-up of Sophia, January 2013
Piloting processes through std IO at the Ruby Drink-up of Sophia, January 2012
DRb at the Ruby Drink-up of Sophia, December 2011
Untitled talk at Riviera.rb
Quines—Programming your way back to where you were
The Dark Side of Programming Languages
Ad

Similar to Ruby C extensions at the Ruby drink-up of Sophia, April 2012 (20)

PPTX
Introduction to Ruby Native Extensions and Foreign Function Interface
PDF
How to write Ruby extensions with Crystal
KEY
Crate - ruby based standalone executables
KEY
Introducing Ruby
PPTX
Extending Ruby using C++
PPTX
sl-unit2 ppt for cse in b.tech jntuh iii year
PDF
Crystal presentation in NY
PPT
What lies beneath the beautiful code?
PDF
Metaprogramming in Ruby
PDF
Ruby confhighlights
PDF
Rubinius - A Tool of the Future
PDF
The details of CI/CD environment for Ruby
PDF
Ruby Presentation - Article
PDF
Crate Packaging Standalone Ruby Applications
PDF
MacRuby & HotCocoa
PDF
ruby-cocoa
PDF
ruby-cocoa
PPT
Ruby Projects and Libraries
PDF
Ruby training day1
Introduction to Ruby Native Extensions and Foreign Function Interface
How to write Ruby extensions with Crystal
Crate - ruby based standalone executables
Introducing Ruby
Extending Ruby using C++
sl-unit2 ppt for cse in b.tech jntuh iii year
Crystal presentation in NY
What lies beneath the beautiful code?
Metaprogramming in Ruby
Ruby confhighlights
Rubinius - A Tool of the Future
The details of CI/CD environment for Ruby
Ruby Presentation - Article
Crate Packaging Standalone Ruby Applications
MacRuby & HotCocoa
ruby-cocoa
ruby-cocoa
Ruby Projects and Libraries
Ruby training day1

Recently uploaded (20)

PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Machine learning based COVID-19 study performance prediction
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
Cloud computing and distributed systems.
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
DOCX
The AUB Centre for AI in Media Proposal.docx
Digital-Transformation-Roadmap-for-Companies.pptx
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Machine learning based COVID-19 study performance prediction
MIND Revenue Release Quarter 2 2025 Press Release
20250228 LYD VKU AI Blended-Learning.pptx
Cloud computing and distributed systems.
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Network Security Unit 5.pdf for BCA BBA.
Dropbox Q2 2025 Financial Results & Investor Presentation
Spectral efficient network and resource selection model in 5G networks
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Diabetes mellitus diagnosis method based random forest with bat algorithm
MYSQL Presentation for SQL database connectivity
Reach Out and Touch Someone: Haptics and Empathic Computing
“AI and Expert System Decision Support & Business Intelligence Systems”
Advanced methodologies resolving dimensionality complications for autism neur...
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
The AUB Centre for AI in Media Proposal.docx

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

  • 1. C extensions easy in Ruby Apr 17th 2012 Muriel Salvan Open Source Lead developer and architect X-Aeon Solutions http://x-aeon.com
  • 5. Ruby and C combined
  • 6. Ruby and C are already coupled Ruby core: around 100 classes written in C (String, Rational, Marshal, IO...) Ruby standard libs: 35 libs written in C: (BigDecimal, Date, OpenSSL...)
  • 7. Now You can write your own C extensions easily
  • 8. What is a C extension ? A requirable library from Ruby code ... require 'myext' … that can use any other Ruby's object or library, … written in C, … and compiled.
  • 9. Technically speaking A C extension is a compiled library (.so or .dll) that: defines 1 specific C function, is accessible in Ruby's load path (same as other .rb files) It is used the same way Ruby's libraries (.rb) are (packaging, search path, require...)
  • 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 Windows Little C knowledge Some Ruby's C API knowledge
  • 11. How to write your C extension
  • 12. Default Ruby program structure myapp/ bin/ exec.rb lib/ myapp/ mylib.rb ext/ myapp/ myext.c extconf.rb myotherlib/ otherlib.c extconf.rb
  • 13. Write the C file ext/myapp/myext.c #include "ruby.h" void Init_myext() { printf("Hello Ruby from C!n"); }
  • 14. Write the extconf file ext/myapp/extconf.rb require 'mkmf' create_makefile('myext') And that's it! Your C extension is ready to be compiled and used
  • 15. How to compile and use your C extension
  • 16. Compile it in ext/myapp/ => ruby extconf.rb creating Makefile => ext/myapp/Makefile => make gcc -I. -I/usr/lib/ruby/1.8/i386-cygwin -I/usr/lib/ruby/1.8/i386-cygwin -I. -g -O2 -c myext.c gcc -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. Use it bin/exec.rb #!/bin/env ruby puts 'Before requiring C extension' require 'myapp/myext' puts 'After requiring C extension' => ruby -Iext bin/exec.rb Before requiring C extension Hello Ruby from C! After requiring C extension
  • 18. And now, package it in a nice Ruby gem!
  • 19. First flavor: Package the compiled extension Add the compiled extension to the files list (like any other library) Add your ext/ directory as a required path Don't forget to set your Gem platform as specific!
  • 20. Platform dependent: gem spec myapp.compiled.gemspec.rb Gem::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 = 'ext' end => 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. Platform dependent: Install and run it => gem install my_app_compiled-0.1-x86- cygwin.gem Successfully installed my_app_compiled-0.1- x86-cygwin 1 gem installed Installing ri documentation for my_app_compiled-0.1-x86-cygwin... Installing RDoc documentation for my_app_compiled-0.1-x86-cygwin... => exec.rb Before requiring C extension Hello Ruby from C! After requiring C extension
  • 22. Second flavor: Platform independent packaging Add the C extension source files to the files list Add your ext/ directory as a required path Keep your Gem platform as Ruby Register the C extension (path to the extconf.rb file)
  • 23. Platform independent: gem spec myapp.gemspec.rb Gem::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. Platform independent: Install and run it => gem install my_app-0.1.gem Building native extensions. This could take a while... Successfully installed my_app-0.1 1 gem installed Installing ri documentation for my_app-0.1... Installing RDoc documentation for my_app-0.1... => exec.rb Before requiring C extension Hello Ruby from C! After requiring C extension
  • 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 to Users do not need install it any development environment
  • 26. Need more than a Hello World ? => The Ruby C API
  • 27. module MyModule class MyClass def my_method(param1, param2, param3) end end end static 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. if param1 == nil puts 'Param1 is nil' return nil else return param1 + 42 end if (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. param2.each do |elem| elemstr = elem.to_s elemstr[0] = 'A' puts elemstr[0..3] end int 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. param3.block_method(3) do | block_param| puts param1 + block_param end static 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. Using external compiled libraries => FFI gem
  • 32. FFI gem Import external functions from a compiled 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. FFI features It has a very intuitive DSL It supports all C native types It supports C structs (also nested), enums and global variables It supports callbacks It has smart methods to handle memory management of pointers and structs
  • 34. Links Makefile generation options: Linuxtopia tutorial mkmf rdoc Ruby C API: Eqqon article Matz' Readme Metaprogramming FFI gem This presentation is available under CC-BY license by Muriel Salvan
  • 35. Q/A