Write Your C Extension for Ruby (Jian Weihang) @tonytonyjan - - PowerPoint PPT Presentation

write your c extension for ruby
SMART_READER_LITE
LIVE PREVIEW

Write Your C Extension for Ruby (Jian Weihang) @tonytonyjan - - PowerPoint PPT Presentation

Write Your C Extension for Ruby (Jian Weihang) @tonytonyjan Bonjour Jian, Weihang tonytonyjan.net tonytonyjan tonytonyjan tonytonyjan tonytonyjan tonytonyjan tonytonyjan Double Keyboard Player Ruby Postgraduate


slide-1
SLIDE 1

Write Your C Extension for Ruby

簡煒航 (Jian Weihang) @tonytonyjan

slide-2
SLIDE 2

Bonjour

slide-3
SLIDE 3
slide-4
SLIDE 4

簡煒航 Jian, Weihang

slide-5
SLIDE 5

tonytonyjan.net

slide-6
SLIDE 6

tonytonyjan

slide-7
SLIDE 7

tonytonyjan

slide-8
SLIDE 8

tonytonyjan

slide-9
SLIDE 9

tonytonyjan

slide-10
SLIDE 10

tonytonyjan

slide-11
SLIDE 11

tonytonyjan

slide-12
SLIDE 12

Double Keyboard Player

slide-13
SLIDE 13

Ruby

slide-14
SLIDE 14

Postgraduate

slide-15
SLIDE 15

Freelancer

slide-16
SLIDE 16

Book Writer

slide-17
SLIDE 17

Coach of Rails Girls Taipei

slide-18
SLIDE 18

Startup

brainana.com 5xruby.tw

slide-19
SLIDE 19

Taiwan

slide-20
SLIDE 20

臺灣(Taiwan)

slide-21
SLIDE 21

臺灣(Taiwan)

slide-22
SLIDE 22

2015-02-18

Montreal Taipei

  • 18°C 19°C
slide-23
SLIDE 23

Happy Chinese New Year

It’s Year of the RAM Ram

slide-24
SLIDE 24

Write Your C Extension for Ruby

簡煒航 (Jian Weihang) @tonytonyjan

slide-25
SLIDE 25

Overview

  • Compilation
  • File Structure
  • Basic MRI API
  • Pointer Wrapper
slide-26
SLIDE 26

Why C Extension?

slide-27
SLIDE 27

Beast from “Kung Fu Hustle”

slide-28
SLIDE 28

“What a fast code!”

slide-29
SLIDE 29

“You code fast!”

slide-30
SLIDE 30

Code Performance vs Development Efficiency

slide-31
SLIDE 31

Performance Development C Ruby Python Perl C++ ASM C Extension

slide-32
SLIDE 32

First step?

slide-33
SLIDE 33

Profiling Tool

gem install ruby-prof

slide-34
SLIDE 34

Jaro-winkler Distance Pure Ruby Implementation

1.6918 ms

slide-35
SLIDE 35

Replace with C Extension

0.5103 ms

slide-36
SLIDE 36

Ruby EXIF Readers

  • mini_exiftool - CLI wrapper of Exiftool
  • exifr - Pure Ruby
  • exif - C Extension of libexif
slide-37
SLIDE 37

tonytonyjan/jaro_winkler tonytonyjan/exif

GitHub

slide-38
SLIDE 38

Make C Extension

slide-39
SLIDE 39

Solutions

  • C API of Ruby
  • rubyinline - mixing C code into Ruby
  • SWIG - Simplified Wrapper and Interface Generator
slide-40
SLIDE 40

rubyinline

slide-41
SLIDE 41

SWIG

$ swig -ruby libfoo.i libfoo_wrap.c foo.c foo.h libfoo.i foo.c foo.h libfoo.so

2k lines

clang/gcc

1 function 1 declaration 3x bigger than MRI C API implementation
slide-42
SLIDE 42

SWIG is similar to C, but not C

slide-43
SLIDE 43

MRI API is just Fine

slide-44
SLIDE 44

What happen in “require”

RbConfig::CONFIG['DLEXT']

foo.so, foo.o and foo.bundle It will load “foo.rb”

slide-45
SLIDE 45

To write a loadable Ruby module is easy.

slide-46
SLIDE 46

What about write a native loadable module?

slide-47
SLIDE 47

Entry of a C Program

slide-48
SLIDE 48

Entry of C Extension

slide-49
SLIDE 49

Compilation

slide-50
SLIDE 50

How to compile?

  • Compile in-line
  • autoconf/pkg-config
  • MakeMakefile (recommended)
slide-51
SLIDE 51

Compile in-line

slide-52
SLIDE 52

pkg-config

slide-53
SLIDE 53

mkmf (Make Makefile)

$ ruby extconf.rb $ make

slide-54
SLIDE 54

installation path

slide-55
SLIDE 55

custom source path

$ ruby extconf.rb $ make

slide-56
SLIDE 56

Conditional Processing

slide-57
SLIDE 57

Conditional Processing

AutoConfig - Generic Header Checks

slide-58
SLIDE 58

Conditional Processing

mkmf methods Compilor Optoins have_header(“foo”)

  • DHAVE_FOO_H

have_library(“foo”)

  • lexif

have_type(“foo”)

  • DHAVE_TYPE_FOO

have_var(“foo”)

  • DHAVE_FOO

have_struct_member('struct foo', 'bar')

  • DHAVE_STRUCT_FOO_BAR

have_func(“foo”)

  • DHAVE_FOO
slide-59
SLIDE 59

It’s just DSL

slide-60
SLIDE 60

Configurable Target Path

slide-61
SLIDE 61

dir_config

slide-62
SLIDE 62

Setup Gemspec

slide-63
SLIDE 63

That’s it

slide-64
SLIDE 64

Yon’t need autotools, mkmf gives you the best.

slide-65
SLIDE 65

File Structure

slide-66
SLIDE 66
slide-67
SLIDE 67

Typical File Structure

mysql2, nokogiri, sqlite3

slide-68
SLIDE 68

It’s ambiguous!

slide-69
SLIDE 69

Better File Structure

pg, bcrypt, eventmachine

slide-70
SLIDE 70

Development Workflow

slide-71
SLIDE 71

`gem install` will generate Makefile & build automatically.

slide-72
SLIDE 72

While developing…

$ cd ext/ $ ruby extconf.rb $ make $ cd .. $ ruby -I ext -r foo_ext -e ‘…’

It’s too tedious.

slide-73
SLIDE 73

Life can be easier.

slide-74
SLIDE 74

gem install rake-compiler

slide-75
SLIDE 75

$ rake -D

slide-76
SLIDE 76

Using rake-compiler

$ rake compile test

slide-77
SLIDE 77

rake-compiler is for development.

slide-78
SLIDE 78

It’s nothing to do with gem installation.

slide-79
SLIDE 79

Basic C API

slide-80
SLIDE 80

Key Knowledge

  • Ruby is OO, C is not.
  • C variables have types but data don’t.
  • Ruby variables have no types but data do.
  • Data in Ruby are represented by C type “VALUE”,

and “VALUE” data has its own data-type.

slide-81
SLIDE 81

Define Module/Class

Ruby C

slide-82
SLIDE 82

Nested Class/Module

Ruby C

slide-83
SLIDE 83
slide-84
SLIDE 84

Define Method

Ruby C

argc function pointer

slide-85
SLIDE 85

Singleton Instance of rb_cNilClass (there are also Qfalse, Qtrue) Convert Ruby String to C String self self

slide-86
SLIDE 86

Ruby data <-> C data

Fixnum Numeric String int FIX2INT(value) INT2FIX(i) NUM2INT(value) INT2NUM(l) long FIX2LONG(value) LONG2FIX(l) NUM2LONG(value) LONG2NUM(l) double NUM2DBL(value) rb_float_new(f) char* StringValueCStr(value) rb_str_new_cstr(s)

slide-87
SLIDE 87

Steps of implementation

slide-88
SLIDE 88

Type Checking

slide-89
SLIDE 89

Ruby C

slide-90
SLIDE 90

internal VALUE Types

T_NIL T_STRING T_STRUCT T_FILE T_OBJECT T_REGEXP T_BIGNUM T_TRUE T_CLASS T_ARRAY T_FIXNUM T_FALSE T_MODULE T_HASH T_COMPLEX T_DATA T_FLOAT T_SYMBOL T_RATIONAL

slide-91
SLIDE 91

Pointer Wrapper

slide-92
SLIDE 92

C is not OOP

slide-93
SLIDE 93

However, there is structure in C.

slide-94
SLIDE 94 char name[20] char desc[20] Wrapped C Struct User instance hello() new() char name[20] char desc[20] Wrapped C Struct User instance hello() new()

u1 = User.new(…) u2 = User.new(…)

slide-95
SLIDE 95
slide-96
SLIDE 96

User#new(name, desc)

Ruby class C struct mark function pointer free function pointer ActiveRecord::Persistence#destroy return

slide-97
SLIDE 97

User#hello

C struct Ruby instance return

slide-98
SLIDE 98

What about C++?

slide-99
SLIDE 99
slide-100
SLIDE 100

That’s it!

slide-101
SLIDE 101

Leaning Resources

  • Official Guide
  • http://guides.rubygems.org/gems-with-extensions/
  • README.EXT in ruby source code
  • @tenderlove
  • http://tenderlovemaking.com/2009/12/18/writing-ruby-c-extensions-
part-1.html
  • http://tenderlovemaking.com/2010/12/11/writing-ruby-c-extensions-
part-2.html
  • Source code of pg, sqlite2, mysql2, nokogiri, kgio, bcrypt, etc
  • MRI source code
slide-102
SLIDE 102

Thanks for your listening