SlideShare a Scribd company logo
1 of 27
Writing a Gem
with native extensions
Tristan Penman
Melbourne Ruby Meetup, August 2018
A whirlwind tour
 What are they?
 Native extensions allow you to extend the functionality
available in Ruby by writing code in natively compiled
languages such as C, C++, or even Rust.
 This talk shows how native extensions can be used to
interact with a third-party library written in C.
 The final code from this talk can be found on Github:
 https://github.com/tristanpenman/simple-clipboard
Native extensions
A brief introduction
Native extensions
Examples
• Byebug - a debugger for Ruby, that uses Ruby's TracePoint API
for execution control and the Debug Inspector API for call
stack navigation. Written as a C extension for speed.
• nokogiri - an HTML and XML parser. Uses native libraries for
speed and ensure standards compliance.
• RMagick - bindings for the ImageMagick image manipulation
library.
• sqlite3 - bindings for the SQLite3 database engine.
libclipboard
 libclipboard is a cross-platform clipboard library
 Simple C-based API:
 clipboard_new - create a context through which to access
the user's clipboard
 clipboard_free - free any memory allocated by
clipboard_new
 clipboard_text - read the contents of the clipboard as text
 clipboard_set_text - replace the contents of the clipboard
with new text
libclipboard
git clone https://github.com/jtanx/libclipboard
cd libclipboard
mkdir build
cd build
cmake ..
make -j4
sudo make install
 Must be built from source
 Requires git, cmake, and a C++ compiler tool-chain:
simple_clipboard
 We will use a native extension to wrap libclipboard with a
Module that we can use in Ruby code:
module SimpleClipboard
def get_text
#TODO: Return current contents ofclipboard,ornil
raise NotImplementedError
end
def set_text(new_text)
#TODO: Update clipboard; return previous contents, ornil
raise NotImplementedError
end
end
Extending Ruby using C
 To create our native extension we need two files:
 extconf.rb
 simple_clipboard.c
Extending Ruby using C
require 'mkmf'
$LOCAL_LIBS << '-lclipboard'
if RUBY_PLATFORM =~ /darwin/
$LDFLAGS <<' -framework AppKit'
end
create_header
create_makefile 'simple_clipboard/simple_clipboard'
extconf.rb
Extending Ruby using C
simple_clipboard.c (1/2)
#include <ruby.h>
#include <libclipboard.h>
VALUEget_text(VALUE _self) {
VALUE result = Qnil;
char *text = clipboard_text(cb);
if (text) {
result =rb_str_new(text, strlen(text));
free(text);
}
return result;
}
// continued on next slide...
Extending Ruby using C
simple_clipboard.c (2/2)
// continued from previous slide
VALUEset_text(VALUE _self, VALUE str) {
// omitted, since it is similar to get_text
}
voidInit_simple_clipboard() {
VALUE m =rb_define_module("SimpleClipboard");
rb_define_module_function(m, "get_text", get_text, 0);
rb_define_module_function(m, "set_text", set_text, 1);
}
 Run 'ruby extconf.rb' to generate:
 Header file (extconf.h, which is redundant in this case)
 Makefile
 (also mkmf.log)
 Run ’make’ to compile the extension
 On Mac OS X, creates a .bundle file
 On Linux, creates a .so
 On Windows, creates a .dll
Extending Ruby using C
2.3.3:001> require './simple_clipboard'
=>true
2.3.3:002> SimpleClipboard.get_text
=>"Extending Ruby using C"
2.3.3:003> SimpleClipboard.set_text "Hello world"
=>"Extending Ruby using C"
2.3.3:004> SimpleClipboard.get_text
=>"Hello world"
Extending Ruby using C
IRB session
Extending Ruby using C
In a nutshell
 For an extension named 'xyz' we need:
 An extconf.rb file and source file called 'xyz.c'
 In the 'xyz.c' file, a function called Init_xyz
 A native extension is free to:
 define modules, classes and methods that operate on
Ruby values, via an opaque C datatype 'VALUE'
 Call existing Ruby code
 Crash the current process
 And more generally, call 'undefined behavior'
How to include C code in a gem
 Okay, safety be damned, we want performance…
or legacy functionality…
or something.
 lib/
 simple_clipboard/
 version.rb
 simple_clipboard.rb
 simple_clipboard.gemspec
How to include C code in a gem
Layout without a native extension
How to include C code in a gem
Layout with a native extension
 ext/
 simple_clipboard/
 extconf.rb
 simple_clipboard.c
 lib/
 simple_clipboard/
 version.rb
 simple_clipboard.rb
 simple_clipboard.gemspec
#Boilerplate omitted
Gem::Specification.new do |s|
s.name ='simple_clipboard'
s.version =SimpleClipboard::VERSION
s.date ='2018-07-24'
s.summary ='Simple clipboardexample gem'
s.authors =['TristanPenman']
s.email ='tristan@tristanpenman.com'
s.licenses =['MIT']
#continued on next slide...
How to include C code in a gem
simple_clipboard.gemspec (1/2)
#continued from previous slide...
s.extensions =['ext/simple_clipboard/extconf.rb']
#Tell bundler where to findthe code forour gem
s.require_paths =['lib']
#Files toinclude in bundle
s.files =['ext/simple_clipboard/simple_clipboard.c',
'lib/simple_clipboard.rb',
'lib/simple_clipboard/version.rb']
end
How to include C code in a gem
simple_clipboard.gemspec (2/2)
How to include C code in a gem
 Run 'gem build simple_clipboard.gemspec':
 Does not actually compile native extension
 Creates 'simple_clipboard-0.0.1.gem'
 Run 'gem install simple_clipboard-0.0.1.gem'
 This is when bundler will build the native extension
 And this why, when things go wrong while building gems
such as nokigiri, that you can get very complex error
messages
$ gem install simple_clipboard-0.0.1.gem
How to include C code in a gem
Example
Building native extensions. This could take a while...
Successfully installed simple_clipboard-0.0.1
Parsing documentation forsimple_clipboard-0.0.1
Done installing documentation for simple_clipboard after 0 seconds
1 gem installed
2.3.3 :001 >require 'simple_clipboard'
=> true
2.3.3 :002 > SimpleClipboard.get_text
=> "Extending Ruby using C"
2.3.3 :003 > SimpleClipboard.set_text "Hello world"
=> "Extending Ruby using C"
2.3.3 :004 > SimpleClipboard.get_text
=> "Hello world"
Extending Ruby using C
IRB session
Testing native extensions
require "bundler/gem_tasks"
require "rspec/core/rake_task"
require 'rake/extensiontask'
desc "simple_clipboard unit tests"
RSpec::Core::RakeTask.new(:spec) do|t|
t.pattern ="spec/*_spec.rb"
t.verbose =true
End
#continued on next slide...
Rakefile (1/2)
Testing native extensions
#continued fromprevious slide
Rake::ExtensionTask.new do|ext|
ext.name ='simple_clipboard'
ext.source_pattern ="*.{c,h}"
ext.ext_dir ='ext/simple_clipboard'
ext.lib_dir ='lib/simple_clipboard'
ext.gem_spec =
Gem::Specification.load('simple_clipboard.gemspec')
end
#Default is tocompile native extension then runtests
task :default =>[:compile, :spec]
Rakefile (2/2)
Testing native extensions
1. Run 'rake' to compile and run tests
2. Run 'rake compile' to only compile native extension
 Compiles the native extension, then copies
simple_clipboard.[bundle|so|dll] file into 'lib/simple_clipboard'
3. Run 'rake spec' to only run tests
 Assumes that native extension (e.g. simple_clipboard.bundle) has
already been copied to 'lib/simple_clipboard' directory
Rake tasks
Resources
• Useful reference implementation of a
Gem with a native extension:
https://github.com/neilslater/ruby_nex_c
• Core documentation:
https://ruby-doc.org/core-
2.3.3/doc/extension_rdoc.html
(Beware the version number in this link)
• Pat Shaughnessy’s book:
Ruby Under a Microscope
Resources
• RubyGems documentation
https://guides.rubygems.org/gems-with-extensions/
• Aaron Bedra's Extending Ruby guide
http://aaronbedra.com/extending-ruby
• Chris Lalancette's in-depth series on writing Ruby extensions
in C, which covers numerous topics:
http://clalance.blogspot.com/2011/01/writing-ruby-
extensions-in-c-part-1.html
(12 parts in total)
Thanks for listening

More Related Content

What's hot

Middleware as Code with mruby
Middleware as Code with mrubyMiddleware as Code with mruby
Middleware as Code with mrubyHiroshi SHIBATA
 
Hijacking Ruby Syntax in Ruby
Hijacking Ruby Syntax in RubyHijacking Ruby Syntax in Ruby
Hijacking Ruby Syntax in RubySATOSHI TAGOMORI
 
How to develop Jenkins plugin using to ruby and Jenkins.rb
How to develop Jenkins plugin using to ruby and Jenkins.rbHow to develop Jenkins plugin using to ruby and Jenkins.rb
How to develop Jenkins plugin using to ruby and Jenkins.rbHiroshi SHIBATA
 
Experiments in Sharing Java VM Technology with CRuby
Experiments in Sharing Java VM Technology with CRubyExperiments in Sharing Java VM Technology with CRuby
Experiments in Sharing Java VM Technology with CRubyMatthew Gaudet
 
How to test code with mruby
How to test code with mrubyHow to test code with mruby
How to test code with mrubyHiroshi SHIBATA
 
Asynchronous I/O in NodeJS - new standard or challenges?
Asynchronous I/O in NodeJS - new standard or challenges?Asynchronous I/O in NodeJS - new standard or challenges?
Asynchronous I/O in NodeJS - new standard or challenges?Dinh Pham
 
How to Begin Developing Ruby Core
How to Begin Developing Ruby CoreHow to Begin Developing Ruby Core
How to Begin Developing Ruby CoreHiroshi SHIBATA
 
Practical Testing of Ruby Core
Practical Testing of Ruby CorePractical Testing of Ruby Core
Practical Testing of Ruby CoreHiroshi SHIBATA
 
Leave end-to-end testing to Capybara
Leave end-to-end testing to CapybaraLeave end-to-end testing to Capybara
Leave end-to-end testing to CapybaraHiroshi SHIBATA
 
The details of CI/CD environment for Ruby
The details of CI/CD environment for RubyThe details of CI/CD environment for Ruby
The details of CI/CD environment for RubyHiroshi SHIBATA
 
Web Development in Perl
Web Development in PerlWeb Development in Perl
Web Development in PerlNaveen Gupta
 
JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015Charles Nutter
 
mruby で mackerel のプラグインを作るはなし
mruby で mackerel のプラグインを作るはなしmruby で mackerel のプラグインを作るはなし
mruby で mackerel のプラグインを作るはなしHiroshi SHIBATA
 
Nodejs Event Driven Concurrency for Web Applications
Nodejs Event Driven Concurrency for Web ApplicationsNodejs Event Driven Concurrency for Web Applications
Nodejs Event Driven Concurrency for Web ApplicationsGanesh Iyer
 
Gate of Agile Web Development
Gate of Agile Web DevelopmentGate of Agile Web Development
Gate of Agile Web DevelopmentKoichi ITO
 
Apache thrift-RPC service cross languages
Apache thrift-RPC service cross languagesApache thrift-RPC service cross languages
Apache thrift-RPC service cross languagesJimmy Lai
 

What's hot (20)

Day CRX Introduction
Day CRX IntroductionDay CRX Introduction
Day CRX Introduction
 
Middleware as Code with mruby
Middleware as Code with mrubyMiddleware as Code with mruby
Middleware as Code with mruby
 
How DSL works on Ruby
How DSL works on RubyHow DSL works on Ruby
How DSL works on Ruby
 
Hijacking Ruby Syntax in Ruby
Hijacking Ruby Syntax in RubyHijacking Ruby Syntax in Ruby
Hijacking Ruby Syntax in Ruby
 
How to develop Jenkins plugin using to ruby and Jenkins.rb
How to develop Jenkins plugin using to ruby and Jenkins.rbHow to develop Jenkins plugin using to ruby and Jenkins.rb
How to develop Jenkins plugin using to ruby and Jenkins.rb
 
Practical ngx_mruby
Practical ngx_mrubyPractical ngx_mruby
Practical ngx_mruby
 
Experiments in Sharing Java VM Technology with CRuby
Experiments in Sharing Java VM Technology with CRubyExperiments in Sharing Java VM Technology with CRuby
Experiments in Sharing Java VM Technology with CRuby
 
How to test code with mruby
How to test code with mrubyHow to test code with mruby
How to test code with mruby
 
Asynchronous I/O in NodeJS - new standard or challenges?
Asynchronous I/O in NodeJS - new standard or challenges?Asynchronous I/O in NodeJS - new standard or challenges?
Asynchronous I/O in NodeJS - new standard or challenges?
 
How to Begin Developing Ruby Core
How to Begin Developing Ruby CoreHow to Begin Developing Ruby Core
How to Begin Developing Ruby Core
 
Practical Testing of Ruby Core
Practical Testing of Ruby CorePractical Testing of Ruby Core
Practical Testing of Ruby Core
 
Leave end-to-end testing to Capybara
Leave end-to-end testing to CapybaraLeave end-to-end testing to Capybara
Leave end-to-end testing to Capybara
 
The details of CI/CD environment for Ruby
The details of CI/CD environment for RubyThe details of CI/CD environment for Ruby
The details of CI/CD environment for Ruby
 
Web Development in Perl
Web Development in PerlWeb Development in Perl
Web Development in Perl
 
JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015JRuby 9000 - Taipei Ruby User's Group 2015
JRuby 9000 - Taipei Ruby User's Group 2015
 
mruby で mackerel のプラグインを作るはなし
mruby で mackerel のプラグインを作るはなしmruby で mackerel のプラグインを作るはなし
mruby で mackerel のプラグインを作るはなし
 
Nodejs Event Driven Concurrency for Web Applications
Nodejs Event Driven Concurrency for Web ApplicationsNodejs Event Driven Concurrency for Web Applications
Nodejs Event Driven Concurrency for Web Applications
 
Gate of Agile Web Development
Gate of Agile Web DevelopmentGate of Agile Web Development
Gate of Agile Web Development
 
RubyGems 3 & 4
RubyGems 3 & 4RubyGems 3 & 4
RubyGems 3 & 4
 
Apache thrift-RPC service cross languages
Apache thrift-RPC service cross languagesApache thrift-RPC service cross languages
Apache thrift-RPC service cross languages
 

Similar to Writing a Gem with native extensions

Ruby C extensions at the Ruby drink-up of Sophia, April 2012
Ruby C extensions at the Ruby drink-up of Sophia, April 2012Ruby C extensions at the Ruby drink-up of Sophia, April 2012
Ruby C extensions at the Ruby drink-up of Sophia, April 2012rivierarb
 
introduction-infra-as-a-code using terraform
introduction-infra-as-a-code using terraformintroduction-infra-as-a-code using terraform
introduction-infra-as-a-code using terraformniyof97
 
Mac ruby deployment
Mac ruby deploymentMac ruby deployment
Mac ruby deploymentThilo Utke
 
Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725miguel dominguez
 
Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725Infrastructureascode slideshare-160331143725
Infrastructureascode slideshare-160331143725MortazaJohari
 
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,...Yevgeniy Brikman
 
DevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux ContainersDevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux Containersinside-BigData.com
 
K8s in 3h - Kubernetes Fundamentals Training
K8s in 3h - Kubernetes Fundamentals TrainingK8s in 3h - Kubernetes Fundamentals Training
K8s in 3h - Kubernetes Fundamentals TrainingPiotr Perzyna
 
A New Chapter of Data Processing with CDK
A New Chapter of Data Processing with CDKA New Chapter of Data Processing with CDK
A New Chapter of Data Processing with CDKShu-Jeng Hsieh
 
Kubered -Recipes for C2 Operations on Kubernetes
Kubered -Recipes for C2 Operations on KubernetesKubered -Recipes for C2 Operations on Kubernetes
Kubered -Recipes for C2 Operations on KubernetesJeffrey Holden
 
Ruby Meets Cocoa
Ruby Meets CocoaRuby Meets Cocoa
Ruby Meets CocoaRobbert
 
The Hitchhiker's Guide to Faster Builds. Viktor Kirilov. CoreHard Spring 2019
The Hitchhiker's Guide to Faster Builds. Viktor Kirilov. CoreHard Spring 2019The Hitchhiker's Guide to Faster Builds. Viktor Kirilov. CoreHard Spring 2019
The Hitchhiker's Guide to Faster Builds. Viktor Kirilov. CoreHard Spring 2019corehard_by
 
Devry gsp 215 week 7 i lab networking and a tiny web server new
Devry gsp 215 week 7 i lab networking and a tiny web server newDevry gsp 215 week 7 i lab networking and a tiny web server new
Devry gsp 215 week 7 i lab networking and a tiny web server newwilliamethan912
 
Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014biicode
 
Build optimization mechanisms in GitLab and Docker
Build optimization mechanisms in GitLab and DockerBuild optimization mechanisms in GitLab and Docker
Build optimization mechanisms in GitLab and DockerDmytro Patkovskyi
 
Toolbox of a Ruby Team
Toolbox of a Ruby TeamToolbox of a Ruby Team
Toolbox of a Ruby TeamArto Artnik
 
stackconf 2022: Cluster Management: Heterogeneous, Lightweight, Safe. Pick Three
stackconf 2022: Cluster Management: Heterogeneous, Lightweight, Safe. Pick Threestackconf 2022: Cluster Management: Heterogeneous, Lightweight, Safe. Pick Three
stackconf 2022: Cluster Management: Heterogeneous, Lightweight, Safe. Pick ThreeNETWAYS
 
5 Things I Wish I Knew About Gitlab CI
5 Things I Wish I Knew About Gitlab CI5 Things I Wish I Knew About Gitlab CI
5 Things I Wish I Knew About Gitlab CISebastian Witowski
 
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ BuilderA Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ BuilderAndrey Karpov
 

Similar to Writing a Gem with native extensions (20)

Ruby C extensions at the Ruby drink-up of Sophia, April 2012
Ruby C extensions at the Ruby drink-up of Sophia, April 2012Ruby C extensions at the Ruby drink-up of Sophia, April 2012
Ruby C extensions at the Ruby drink-up of Sophia, April 2012
 
introduction-infra-as-a-code using terraform
introduction-infra-as-a-code using terraformintroduction-infra-as-a-code using terraform
introduction-infra-as-a-code using terraform
 
Mac ruby deployment
Mac ruby deploymentMac ruby deployment
Mac ruby deployment
 
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,...
 
DevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux ContainersDevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux Containers
 
K8s in 3h - Kubernetes Fundamentals Training
K8s in 3h - Kubernetes Fundamentals TrainingK8s in 3h - Kubernetes Fundamentals Training
K8s in 3h - Kubernetes Fundamentals Training
 
A New Chapter of Data Processing with CDK
A New Chapter of Data Processing with CDKA New Chapter of Data Processing with CDK
A New Chapter of Data Processing with CDK
 
Kubered -Recipes for C2 Operations on Kubernetes
Kubered -Recipes for C2 Operations on KubernetesKubered -Recipes for C2 Operations on Kubernetes
Kubered -Recipes for C2 Operations on Kubernetes
 
Ruby Meets Cocoa
Ruby Meets CocoaRuby Meets Cocoa
Ruby Meets Cocoa
 
The Hitchhiker's Guide to Faster Builds. Viktor Kirilov. CoreHard Spring 2019
The Hitchhiker's Guide to Faster Builds. Viktor Kirilov. CoreHard Spring 2019The Hitchhiker's Guide to Faster Builds. Viktor Kirilov. CoreHard Spring 2019
The Hitchhiker's Guide to Faster Builds. Viktor Kirilov. CoreHard Spring 2019
 
Devry gsp 215 week 7 i lab networking and a tiny web server new
Devry gsp 215 week 7 i lab networking and a tiny web server newDevry gsp 215 week 7 i lab networking and a tiny web server new
Devry gsp 215 week 7 i lab networking and a tiny web server new
 
Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014
 
Build optimization mechanisms in GitLab and Docker
Build optimization mechanisms in GitLab and DockerBuild optimization mechanisms in GitLab and Docker
Build optimization mechanisms in GitLab and Docker
 
Toolbox of a Ruby Team
Toolbox of a Ruby TeamToolbox of a Ruby Team
Toolbox of a Ruby Team
 
stackconf 2022: Cluster Management: Heterogeneous, Lightweight, Safe. Pick Three
stackconf 2022: Cluster Management: Heterogeneous, Lightweight, Safe. Pick Threestackconf 2022: Cluster Management: Heterogeneous, Lightweight, Safe. Pick Three
stackconf 2022: Cluster Management: Heterogeneous, Lightweight, Safe. Pick Three
 
5 Things I Wish I Knew About Gitlab CI
5 Things I Wish I Knew About Gitlab CI5 Things I Wish I Knew About Gitlab CI
5 Things I Wish I Knew About Gitlab CI
 
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ BuilderA Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
 
ABCs of docker
ABCs of dockerABCs of docker
ABCs of docker
 

Recently uploaded

SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Hyundai Motor Group
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsSnow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsHyundai Motor Group
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 

Recently uploaded (20)

SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsSnow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 

Writing a Gem with native extensions

  • 1. Writing a Gem with native extensions Tristan Penman Melbourne Ruby Meetup, August 2018 A whirlwind tour
  • 2.  What are they?  Native extensions allow you to extend the functionality available in Ruby by writing code in natively compiled languages such as C, C++, or even Rust.  This talk shows how native extensions can be used to interact with a third-party library written in C.  The final code from this talk can be found on Github:  https://github.com/tristanpenman/simple-clipboard Native extensions A brief introduction
  • 3. Native extensions Examples • Byebug - a debugger for Ruby, that uses Ruby's TracePoint API for execution control and the Debug Inspector API for call stack navigation. Written as a C extension for speed. • nokogiri - an HTML and XML parser. Uses native libraries for speed and ensure standards compliance. • RMagick - bindings for the ImageMagick image manipulation library. • sqlite3 - bindings for the SQLite3 database engine.
  • 4. libclipboard  libclipboard is a cross-platform clipboard library  Simple C-based API:  clipboard_new - create a context through which to access the user's clipboard  clipboard_free - free any memory allocated by clipboard_new  clipboard_text - read the contents of the clipboard as text  clipboard_set_text - replace the contents of the clipboard with new text
  • 5. libclipboard git clone https://github.com/jtanx/libclipboard cd libclipboard mkdir build cd build cmake .. make -j4 sudo make install  Must be built from source  Requires git, cmake, and a C++ compiler tool-chain:
  • 6. simple_clipboard  We will use a native extension to wrap libclipboard with a Module that we can use in Ruby code: module SimpleClipboard def get_text #TODO: Return current contents ofclipboard,ornil raise NotImplementedError end def set_text(new_text) #TODO: Update clipboard; return previous contents, ornil raise NotImplementedError end end
  • 7. Extending Ruby using C  To create our native extension we need two files:  extconf.rb  simple_clipboard.c
  • 8. Extending Ruby using C require 'mkmf' $LOCAL_LIBS << '-lclipboard' if RUBY_PLATFORM =~ /darwin/ $LDFLAGS <<' -framework AppKit' end create_header create_makefile 'simple_clipboard/simple_clipboard' extconf.rb
  • 9. Extending Ruby using C simple_clipboard.c (1/2) #include <ruby.h> #include <libclipboard.h> VALUEget_text(VALUE _self) { VALUE result = Qnil; char *text = clipboard_text(cb); if (text) { result =rb_str_new(text, strlen(text)); free(text); } return result; } // continued on next slide...
  • 10. Extending Ruby using C simple_clipboard.c (2/2) // continued from previous slide VALUEset_text(VALUE _self, VALUE str) { // omitted, since it is similar to get_text } voidInit_simple_clipboard() { VALUE m =rb_define_module("SimpleClipboard"); rb_define_module_function(m, "get_text", get_text, 0); rb_define_module_function(m, "set_text", set_text, 1); }
  • 11.  Run 'ruby extconf.rb' to generate:  Header file (extconf.h, which is redundant in this case)  Makefile  (also mkmf.log)  Run ’make’ to compile the extension  On Mac OS X, creates a .bundle file  On Linux, creates a .so  On Windows, creates a .dll Extending Ruby using C
  • 12. 2.3.3:001> require './simple_clipboard' =>true 2.3.3:002> SimpleClipboard.get_text =>"Extending Ruby using C" 2.3.3:003> SimpleClipboard.set_text "Hello world" =>"Extending Ruby using C" 2.3.3:004> SimpleClipboard.get_text =>"Hello world" Extending Ruby using C IRB session
  • 13. Extending Ruby using C In a nutshell  For an extension named 'xyz' we need:  An extconf.rb file and source file called 'xyz.c'  In the 'xyz.c' file, a function called Init_xyz  A native extension is free to:  define modules, classes and methods that operate on Ruby values, via an opaque C datatype 'VALUE'  Call existing Ruby code  Crash the current process  And more generally, call 'undefined behavior'
  • 14. How to include C code in a gem  Okay, safety be damned, we want performance… or legacy functionality… or something.
  • 15.  lib/  simple_clipboard/  version.rb  simple_clipboard.rb  simple_clipboard.gemspec How to include C code in a gem Layout without a native extension
  • 16. How to include C code in a gem Layout with a native extension  ext/  simple_clipboard/  extconf.rb  simple_clipboard.c  lib/  simple_clipboard/  version.rb  simple_clipboard.rb  simple_clipboard.gemspec
  • 17. #Boilerplate omitted Gem::Specification.new do |s| s.name ='simple_clipboard' s.version =SimpleClipboard::VERSION s.date ='2018-07-24' s.summary ='Simple clipboardexample gem' s.authors =['TristanPenman'] s.email ='tristan@tristanpenman.com' s.licenses =['MIT'] #continued on next slide... How to include C code in a gem simple_clipboard.gemspec (1/2)
  • 18. #continued from previous slide... s.extensions =['ext/simple_clipboard/extconf.rb'] #Tell bundler where to findthe code forour gem s.require_paths =['lib'] #Files toinclude in bundle s.files =['ext/simple_clipboard/simple_clipboard.c', 'lib/simple_clipboard.rb', 'lib/simple_clipboard/version.rb'] end How to include C code in a gem simple_clipboard.gemspec (2/2)
  • 19. How to include C code in a gem  Run 'gem build simple_clipboard.gemspec':  Does not actually compile native extension  Creates 'simple_clipboard-0.0.1.gem'  Run 'gem install simple_clipboard-0.0.1.gem'  This is when bundler will build the native extension  And this why, when things go wrong while building gems such as nokigiri, that you can get very complex error messages
  • 20. $ gem install simple_clipboard-0.0.1.gem How to include C code in a gem Example Building native extensions. This could take a while... Successfully installed simple_clipboard-0.0.1 Parsing documentation forsimple_clipboard-0.0.1 Done installing documentation for simple_clipboard after 0 seconds 1 gem installed
  • 21. 2.3.3 :001 >require 'simple_clipboard' => true 2.3.3 :002 > SimpleClipboard.get_text => "Extending Ruby using C" 2.3.3 :003 > SimpleClipboard.set_text "Hello world" => "Extending Ruby using C" 2.3.3 :004 > SimpleClipboard.get_text => "Hello world" Extending Ruby using C IRB session
  • 22. Testing native extensions require "bundler/gem_tasks" require "rspec/core/rake_task" require 'rake/extensiontask' desc "simple_clipboard unit tests" RSpec::Core::RakeTask.new(:spec) do|t| t.pattern ="spec/*_spec.rb" t.verbose =true End #continued on next slide... Rakefile (1/2)
  • 23. Testing native extensions #continued fromprevious slide Rake::ExtensionTask.new do|ext| ext.name ='simple_clipboard' ext.source_pattern ="*.{c,h}" ext.ext_dir ='ext/simple_clipboard' ext.lib_dir ='lib/simple_clipboard' ext.gem_spec = Gem::Specification.load('simple_clipboard.gemspec') end #Default is tocompile native extension then runtests task :default =>[:compile, :spec] Rakefile (2/2)
  • 24. Testing native extensions 1. Run 'rake' to compile and run tests 2. Run 'rake compile' to only compile native extension  Compiles the native extension, then copies simple_clipboard.[bundle|so|dll] file into 'lib/simple_clipboard' 3. Run 'rake spec' to only run tests  Assumes that native extension (e.g. simple_clipboard.bundle) has already been copied to 'lib/simple_clipboard' directory Rake tasks
  • 25. Resources • Useful reference implementation of a Gem with a native extension: https://github.com/neilslater/ruby_nex_c • Core documentation: https://ruby-doc.org/core- 2.3.3/doc/extension_rdoc.html (Beware the version number in this link) • Pat Shaughnessy’s book: Ruby Under a Microscope
  • 26. Resources • RubyGems documentation https://guides.rubygems.org/gems-with-extensions/ • Aaron Bedra's Extending Ruby guide http://aaronbedra.com/extending-ruby • Chris Lalancette's in-depth series on writing Ruby extensions in C, which covers numerous topics: http://clalance.blogspot.com/2011/01/writing-ruby- extensions-in-c-part-1.html (12 parts in total)