Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Native Extensions Served 3 Ways
Search
Tejas Dinkar
January 03, 2014
Technology
0
350
Native Extensions Served 3 Ways
This talk was given at Garden City Ruby Conf 2014
Tejas Dinkar
January 03, 2014
Tweet
Share
More Decks by Tejas Dinkar
See All by Tejas Dinkar
Quick Wins for Page Speed
gja
0
130
Progressive Web Apps In Clojure(Script)
gja
4
2.4k
Monads you've already put in production (without knowing it)
gja
1
1.2k
Lightning - Monads you already use (without knowing it)
gja
1
400
Other Decks in Technology
See All in Technology
20251027_findyさん_音声エージェントLT
almondo_event
2
510
初海外がre:Inventだった人間の感じたこと
tommy0124
1
130
dbtとAIエージェントを組み合わせて見えたデータ調査の新しい形
10xinc
7
1.6k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
2
190
re:Invent 2025の見どころと便利アイテムをご紹介 / Highlights and Useful Items for re:Invent 2025
yuj1osm
0
460
組織全員で向き合うAI Readyなデータ利活用
gappy50
5
1.9k
abema-trace-sampling-observability-cost-optimization
tetsuya28
0
390
20251029_Cursor Meetup Tokyo #02_MK_「あなたのAI、私のシェル」 - プロンプトインジェクションによるエージェントのハイジャック
mk0721
PRO
6
2.1k
パフォーマンスチューニングのために普段からできること/Performance Tuning: Daily Practices
fujiwara3
2
180
プロファイルとAIエージェントによる効率的なデバッグ / Effective debugging with profiler and AI assistant
ymotongpoo
1
610
Kotlinで型安全にバイテンポラルデータを扱いたい! ReladomoラッパーをAIと実装してみた話
itohiro73
3
120
実践マルチモーダル検索!
shibuiwilliam
2
470
Featured
See All Featured
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.2k
Bash Introduction
62gerente
615
210k
Stop Working from a Prison Cell
hatefulcrawdad
272
21k
Making Projects Easy
brettharned
120
6.4k
The Art of Programming - Codeland 2020
erikaheidi
56
14k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
116
20k
Speed Design
sergeychernyshev
32
1.2k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
359
30k
Building Applications with DynamoDB
mza
96
6.7k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
650
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.3k
How to Think Like a Performance Engineer
csswizardry
27
2.2k
Transcript
Native Extensions Served 3 Ways Tejas Dinkar Nilenso Software
about.me • Hi, I’m Tejas • Nilenso: Partner • twitter:
tdinkar • github: gja
about.talk • Expect to see lots of code • Will
have about 5 minutes for questions • Please laugh at my jokes! • Will cover C Extensions, FFI and SWIG
Native Extensions • Integrate with new libraries • Improve Performance
of critical code • Write code that works across languages • Feel super 1337
Let’s talk about Python • Pythonista’s in the house? •
Yes, I’m trolling you! http://montgomeryq.blogspot.in/2011/05/random-illustration-tuesday-python-ruby.html
None
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
Require Files? static PyObject *python_ruby_require(PyObject *self, PyObject *file) { rb_require(PyString_AsString(file));
return Py_True; }
Congrats!
Common Fears MEMORY ALLOCATION!?
Memory Management • Data_Wrap_Struct(klass, mark_cb, free_cb, *data) • Data_Get_Struct( VALUE,
data_type, data* )
Common Fears
Portability http://geekandpoke.typepad.com/geekandpoke/2008/05/the-history-of.html
void Init_String(void) {! rb_cString = rb_define_class("String", rb_cObject);! // ...! rb_define_method(rb_cString,
"eql?", rb_str_eql, 1);! rb_define_method(rb_cString, "==", rb_str_equal, 1);! // ...! rb_define_method(rb_cString, "insert", rb_str_insert, 2);! rb_define_method(rb_cString, "length", rb_str_length, 0);! // ...! }! ! static VALUE rb_str_eql(VALUE self, VALUE str2)! {! if (self == str2) return Qtrue;! if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;! return str_eql(self, str2);! }! string.c
void Init_String(void) {! rb_cString = rb_define_class("String", rb_cObject);! // ...! rb_define_method(rb_cString,
"eql?", rb_str_eql, 1);! rb_define_method(rb_cString, "==", rb_str_equal, 1);! // ...! rb_define_method(rb_cString, "insert", rb_str_insert, 2);! rb_define_method(rb_cString, "length", rb_str_length, 0);! // ...! }! ! static VALUE rb_str_eql(VALUE str2, VALUE str2)! {! if (self == str2) return Qtrue;! if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;! return str_eql(self, str2);! }! string.c
void Init_String(void) {! rb_cString = rb_define_class("String", rb_cObject);! // ...! rb_define_method(rb_cString,
"eql?", rb_str_eql, 1);! rb_define_method(rb_cString, "==", rb_str_equal, 1);! // ...! rb_define_method(rb_cString, "insert", rb_str_insert, 2);! rb_define_method(rb_cString, "length", rb_str_length, 0);! // ...! }! ! static VALUE rb_str_eql(VALUE str2, VALUE str2)! {! if (self == str2) return Qtrue;! if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;! return str_eql(self, str2);! }! string.c
C Extensions Native Code Ruby Code Ruby Aware! Native Code
Foreign Function Interface Native Code Ruby Code Native Aware! Ruby
Code
Foreign Function Interface • A Ruby DSL • Works across
all Ruby Implementations • Converts to and from C primitives for you
example require 'ffi'! ! module MyLib! extend FFI::Library! ffi_lib 'c'!
attach_function :puts, [:string], :int! end! ! MyLib.puts 'Hello, World using libc!'
another example require 'ffi'! ! module MyMathLib! extend FFI::Library! ffi_lib
'm'! attach_function :pow, [:double, :double],! :double! end! ! MyMathLib.pow(4, 5) # => 1024.0
Lots of built in types Numbers!! ! ! ! !
Character!! ! ! ! ! Other! :int! ! ! ! ! ! ! :char!! ! ! ! ! ! ! :pointer! :short! ! ! ! ! ! :string! :long! :double! :float!
Foreign Function Interface • Probably your best solution • It’s
really easy • Do your modelling in Ruby • Still have to worry about GC • Sadly, no C++ without wrapping
Memory in FFI def run_query_which_will_crash! db_connection = MyFFIModule.database_connection("localhost")! MyFFIModule.database_query(db_connection, "select
* from users")! end!
Memory in FFI def run_query_which_will_crash! db_connection = MyFFIModule.database_connection("localhost")! MyFFIModule.database_query(db_connection, "select
* from users")! end! This will get GCed
SWIG • Simplified Wrapper and Interface Generator • Annotate your
C/C++ header files • It generates native extensions for languages • About 20 languages currently supported
SWIG Native Code Ruby Code Magic Python Code
The Magic • Takes an interface file • Auto generates
code to make it work • For ruby, it’s a `regular’ C extension • For python, it’s a a .c and .py file • For Java it’s a JNI interface • Still need to do your own GC
The Rectangle class Rectangle! {! int length;! int breadth;! !
public:! Rectangle(int length, int breadth);! int area();! };
The Rectangle class Rectangle! {! int length;! int breadth;! !
public:! Rectangle(int length, int breadth);! int area();! }; #ifdef SWIG %module shape %{ %} SWIG Stuff Here
require 'shapes'! ! rectangle = shapes.Rectangle.new(10, 12)! rectangle.area == 120!
Other Options • DL (Dynamic Load) • Fiddle(r)
TL;DR • Native Extensions are fun and easy to build
• The three big tools • You want to pick FFI if you don’t maintain the lib • SWIG may be better if you are a maintainer
Thank You Many Questions? wow so native so extension wow
no python such easy such performance super integration ruby = win