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
330
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
110
Progressive Web Apps In Clojure(Script)
gja
4
2.3k
Monads you've already put in production (without knowing it)
gja
1
1.1k
Lightning - Monads you already use (without knowing it)
gja
1
340
Other Decks in Technology
See All in Technology
複雑性の高いオブジェクト編集に向き合う: プラガブルなReactフォーム設計
righttouch
PRO
0
110
KubeCon NA 2024 Recap: How to Move from Ingress to Gateway API with Minimal Hassle
ysakotch
0
200
AWS re:Invent 2024 ふりかえり
kongmingstrap
0
130
alecthomas/kong はいいぞ / kamakura.go#7
fujiwara3
1
300
LINEスキマニにおけるフロントエンド開発
lycorptech_jp
PRO
0
330
スタートアップで取り組んでいるAzureとMicrosoft 365のセキュリティ対策/How to Improve Azure and Microsoft 365 Security at Startup
yuj1osm
0
210
watsonx.ai Dojo #5 ファインチューニングとInstructLAB
oniak3ibm
PRO
0
160
祝!Iceberg祭開幕!re:Invent 2024データレイク関連アップデート10分総ざらい
kniino
2
260
UI State設計とテスト方針
rmakiyama
2
540
開発生産性向上! 育成を「改善」と捉えるエンジニア育成戦略
shoota
2
330
マルチプロダクト開発の現場でAWS Security Hubを1年以上運用して得た教訓
muziyoshiz
2
2.2k
統計データで2024年の クラウド・インフラ動向を眺める
ysknsid25
2
840
Featured
See All Featured
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.6k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
5
440
Designing on Purpose - Digital PM Summit 2013
jponch
116
7k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
232
17k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
48
2.2k
Music & Morning Musume
bryan
46
6.2k
Java REST API Framework Comparison - PWX 2021
mraible
PRO
28
8.3k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
26
1.9k
We Have a Design System, Now What?
morganepeng
51
7.3k
Docker and Python
trallard
42
3.1k
How to Ace a Technical Interview
jacobian
276
23k
Adopting Sorbet at Scale
ufuk
73
9.1k
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