SlideShare ist ein Scribd-Unternehmen logo
1 von 35
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

Weitere Àhnliche Inhalte

Was ist angesagt?

[Doc] Java: The Complete Reference, Tenth Edition (Complete Reference Series)
[Doc] Java: The Complete Reference, Tenth Edition (Complete Reference Series)[Doc] Java: The Complete Reference, Tenth Edition (Complete Reference Series)
[Doc] Java: The Complete Reference, Tenth Edition (Complete Reference Series)
birumudare12
 
Object-oriented Programming-with C#
Object-oriented Programming-with C#Object-oriented Programming-with C#
Object-oriented Programming-with C#
Doncho Minkov
 

Was ist angesagt? (20)

SOLID Principles and Design Patterns
SOLID Principles and Design PatternsSOLID Principles and Design Patterns
SOLID Principles and Design Patterns
 
Inheritance in oops
Inheritance in oopsInheritance in oops
Inheritance in oops
 
[Doc] Java: The Complete Reference, Tenth Edition (Complete Reference Series)
[Doc] Java: The Complete Reference, Tenth Edition (Complete Reference Series)[Doc] Java: The Complete Reference, Tenth Edition (Complete Reference Series)
[Doc] Java: The Complete Reference, Tenth Edition (Complete Reference Series)
 
Intro to Linux Shell Scripting
Intro to Linux Shell ScriptingIntro to Linux Shell Scripting
Intro to Linux Shell Scripting
 
Data abstraction and object orientation
Data abstraction and object orientationData abstraction and object orientation
Data abstraction and object orientation
 
Array and functions
Array and functionsArray and functions
Array and functions
 
Polymorphism
PolymorphismPolymorphism
Polymorphism
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and Fold
 
Polymorphism in c++(ppt)
Polymorphism in c++(ppt)Polymorphism in c++(ppt)
Polymorphism in c++(ppt)
 
C++ Inheritance Tutorial | Introduction To Inheritance In C++ Programming Wit...
C++ Inheritance Tutorial | Introduction To Inheritance In C++ Programming Wit...C++ Inheritance Tutorial | Introduction To Inheritance In C++ Programming Wit...
C++ Inheritance Tutorial | Introduction To Inheritance In C++ Programming Wit...
 
Perl names values and variables
Perl names values and variablesPerl names values and variables
Perl names values and variables
 
Inheritance in OOPS
Inheritance in OOPSInheritance in OOPS
Inheritance in OOPS
 
C++11 & C++14
C++11 & C++14C++11 & C++14
C++11 & C++14
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
 
Object-oriented Programming-with C#
Object-oriented Programming-with C#Object-oriented Programming-with C#
Object-oriented Programming-with C#
 
Modular programming
Modular programmingModular programming
Modular programming
 
Polymorphism in oop
Polymorphism in oopPolymorphism in oop
Polymorphism in oop
 
Namespaces in C#
Namespaces in C#Namespaces in C#
Namespaces in C#
 
Abstraction in c++ and Real Life Example of Abstraction in C++
Abstraction in c++ and Real Life Example of Abstraction in C++Abstraction in c++ and Real Life Example of Abstraction in C++
Abstraction in c++ and Real Life Example of Abstraction in C++
 
two tier and three tier
two tier and three tiertwo tier and three tier
two tier and three tier
 

Andere mochten auch

Andere mochten auch (10)

Ruby and Docker on Rails
Ruby and Docker on RailsRuby and Docker on Rails
Ruby and Docker on Rails
 
Pry at the Ruby Drink-up of Sophia, February 2012
Pry at the Ruby Drink-up of Sophia, February 2012Pry at the Ruby Drink-up of Sophia, February 2012
Pry at the Ruby Drink-up of Sophia, February 2012
 
Ruby 2.0 at the Ruby drink-up of Sophia, February 2013
Ruby 2.0 at the Ruby drink-up of Sophia, February 2013Ruby 2.0 at the Ruby drink-up of Sophia, February 2013
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 and Twitter at the Ruby drink-up of Sophia, January 2013Ruby and Twitter at the Ruby drink-up of Sophia, January 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
Ruby object model at the Ruby drink-up of Sophia, January 2013Ruby object model 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
Piloting processes through std IO at the Ruby Drink-up of Sophia, January 2012Piloting processes through std IO at the Ruby Drink-up of Sophia, January 2012
Piloting processes through std IO at the Ruby Drink-up of Sophia, January 2012
 
DRb at the Ruby Drink-up of Sophia, December 2011
DRb at the Ruby Drink-up of Sophia, December 2011DRb at the Ruby Drink-up of Sophia, December 2011
DRb at the Ruby Drink-up of Sophia, December 2011
 
Untitled talk at Riviera.rb
Untitled talk at Riviera.rbUntitled talk at Riviera.rb
Untitled talk at Riviera.rb
 
Quines—Programming your way back to where you were
Quines—Programming your way back to where you wereQuines—Programming your way back to where you were
Quines—Programming your way back to where you were
 
The Dark Side of Programming Languages
The Dark Side of Programming LanguagesThe Dark Side of Programming Languages
The Dark Side of Programming Languages
 

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

A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
旻琊 朘
 
Intro to Rack
Intro to RackIntro to Rack
Intro to Rack
Rubyc Slides
 
Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3
Clinton Dreisbach
 

Ähnlich wie Ruby C extensions at the Ruby drink-up of Sophia, April 2012 (20)

Writing a Gem with native extensions
Writing a Gem with native extensionsWriting a Gem with native extensions
Writing a Gem with native extensions
 
Introduction to Rails - presented by Arman Ortega
Introduction to Rails - presented by Arman OrtegaIntroduction to Rails - presented by Arman Ortega
Introduction to Rails - presented by Arman Ortega
 
Mac ruby deployment
Mac ruby deploymentMac ruby deployment
Mac ruby deployment
 
Toolbox of a Ruby Team
Toolbox of a Ruby TeamToolbox of a Ruby Team
Toolbox of a Ruby Team
 
Rails web api ćŒ€ć‘
Rails web api ćŒ€ć‘Rails web api ćŒ€ć‘
Rails web api ćŒ€ć‘
 
Infrastructure as code - Python Saati #36
Infrastructure as code - Python Saati #36Infrastructure as code - Python Saati #36
Infrastructure as code - Python Saati #36
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
 
How to write Ruby extensions with Crystal
How to write Ruby extensions with CrystalHow to write Ruby extensions with Crystal
How to write Ruby extensions with Crystal
 
Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725
 
Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725
 
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
 
What lies beneath the beautiful code?
What lies beneath the beautiful code?What lies beneath the beautiful code?
What lies beneath the beautiful code?
 
Sinatra for REST services
Sinatra for REST servicesSinatra for REST services
Sinatra for REST services
 
#CNX14 - Using Ruby for Reliability, Consistency, and Speed
#CNX14 - Using Ruby for Reliability, Consistency, and Speed#CNX14 - Using Ruby for Reliability, Consistency, and Speed
#CNX14 - Using Ruby for Reliability, Consistency, and Speed
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
Middleware as Code with mruby
Middleware as Code with mrubyMiddleware as Code with mruby
Middleware as Code with mruby
 
Intro to Rack
Intro to RackIntro to Rack
Intro to Rack
 
Rails Engine | Modular application
Rails Engine | Modular applicationRails Engine | Modular application
Rails Engine | Modular application
 
What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...
What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...
What's new and great in Rails 3 - Matt Gauger - Milwaukee Ruby Users Group De...
 
Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3
 

KĂŒrzlich hochgeladen

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

KĂŒrzlich hochgeladen (20)

Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 

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