1 of 154

Building Native Extensions

This Could Take A While ...

Mike Dalessio

@flavorjones

RubyConf 2021

2 of 154

Mike Dalessio

@flavorjones

I work at Shopify

I maintain Nokogiri

3 of 154

Preface

4 of 154

5 of 154

6 of 154

bit.ly/rcee-gems

flavorjones/ruby-c-extensions-explained

7 of 154

Only a Few Basic Patterns

“Isolated”

“System”

“Packaged Source”

“Packaged Tarball”

“Precompiled”

8 of 154

Ruby Kaigi talk

Was a

HOW-TO

9 of 154

Today we’ll also cover the

“WHY?”

10 of 154

11 of 154

Things I will talk about today

  1. Ruby C Extensions, Explained (15 min)
  2. Why Most Gems Shouldn’t Be Precompiled
  3. Why Precompiled Nokogiri is a Good Thing™
  4. A Note about Trust
  5. Q&A (if we have time 😰)

12 of 154

What is a

C Extension?

13 of 154

14 of 154

15 of 154

16 of 154

Show me a

C extension!

17 of 154

Let’s look at the “Isolated”

gem

18 of 154

19 of 154

20 of 154

21 of 154

22 of 154

23 of 154

I need more details, plz!

24 of 154

25 of 154

26 of 154

27 of 154

28 of 154

29 of 154

30 of 154

31 of 154

32 of 154

33 of 154

34 of 154

35 of 154

36 of 154

37 of 154

What can go wrong

when installing C extensions?

38 of 154

1. Compiler Toolchain Not Installed

39 of 154

40 of 154

41 of 154

42 of 154

43 of 154

44 of 154

45 of 154

46 of 154

47 of 154

What problems can a C Extension solve?

48 of 154

Talk to�Third-party

Libraries

49 of 154

50 of 154

51 of 154

52 of 154

Examples of gems using third-party libraries

nokogiri

psych

sqlite3

rmagick

grpc

libxml2, libxslt, libgumbo

libyaml

libsqlite3

libMagick

libgrpc

53 of 154

Are there other ways to call third-party libraries?

54 of 154

55 of 154

56 of 154

Show me

how to use an external library!

57 of 154

58 of 154

bit.ly/rcee-gems

flavorjones/ruby-c-extensions-explained

59 of 154

Strategy #1: “system” libraries

gem install rcee_system

60 of 154

61 of 154

62 of 154

63 of 154

64 of 154

65 of 154

66 of 154

67 of 154

68 of 154

What tends to break when using the “System” strategy?

  • Installing third party libs
  • Nonstandard install dirs
  • Version too old or too new
  • Compile-time feature missing

69 of 154

70 of 154

Strategy #2: “Packaged” libraries

gem install rcee_packaged_tarball

71 of 154

72 of 154

73 of 154

74 of 154

75 of 154

76 of 154

77 of 154

78 of 154

Good and Bad about the “Packaged Tarball” Strategy

Good

  • Known-good version of the library

Bad

  • Now I have to keep the library up-to-date for my users

79 of 154

80 of 154

User Satisfaction

81 of 154

82 of 154

83 of 154

Strategy #3: “Precompiled” libraries

gem install rcee_precompiled

84 of 154

85 of 154

86 of 154

87 of 154

88 of 154

89 of 154

90 of 154

91 of 154

92 of 154

93 of 154

94 of 154

95 of 154

96 of 154

97 of 154

98 of 154

99 of 154

100 of 154

101 of 154

102 of 154

103 of 154

“Precompiled” strategy risks

Ruby version 🗹

Platform 🗹

System libraries (gnu vs musl) 😜

104 of 154

Mitigation:

Test All The F’n TimE

105 of 154

106 of 154

107 of 154

108 of 154

109 of 154

Unfortunately, this doesn’t currently test musl/alpine

110 of 154

Why Most Gems Shouldn’t Be Precompiled

111 of 154

112 of 154

“Goodbye Fat gem” raises some good points

  1. Users can’t use the latest Ruby until every precompiled gem has shipped with support

113 of 154

“Goodbye Fat gem” raises some good points

  • Users can’t use the latest Ruby until every precompiled gem has shipped with support

114 of 154

“Goodbye Fat gem” raises some good points

  • Users can’t use the latest Ruby until every precompiled gem has shipped with support
  • Upstream patches to the third-party library may get delayed

115 of 154

“Goodbye Fat gem” raises some good points

  • Users can’t use the latest Ruby until every precompiled gem has shipped with support
  • Upstream patches to the third-party library may get delayed
  • Users cannot control the version of the library used

116 of 154

“Goodbye Fat gem” raises some good points

  • Users can’t use the latest Ruby until every precompiled gem has shipped with support
  • Upstream patches to the third-party library may get delayed
  • Users cannot control the version of the library used
  • High maintenance cost, complex build process

117 of 154

“Goodbye Fat gem” raises some good points

  • Users can’t use the latest Ruby until every precompiled gem has shipped with support
  • Upstream patches to the third-party library may get delayed
  • Users cannot control the version of the library used
  • High maintenance cost, complex build process
  • Optimizations aren’t enabled for specific platforms (e.g., “-march=native -O3”)

118 of 154

Why Precompiled Nokogiri is a Good Thing™

119 of 154

Why Precompiled Nokogiri is a Good Thing™

(For me)

120 of 154

Fewer Support Issues

In 2020, just over 1 per week.

In 2021, just over 1 per month.

121 of 154

Why Precompiled Nokogiri is a Good Thing™

(For you)

122 of 154

Fewer Struggling Users

YoY, page hits on installation docs are down ~30%

(Page hits on nokogiri.org are up ~20% in the same period)

123 of 154

Fewer Angry Complaints

Nearly zero four-letter-words uttered on Twitter

(except for folks on older versions! 🤪)

124 of 154

Why Precompiled Nokogiri is a Good Thing™

(For the universe)

125 of 154

Nokogiri is Webscale™, I guess

Nokogiri precompiled downloads since v1.11.0 (2021-01-03):

Total: 60,743,405

x86_64-linux: 56,055,797 (88.38%)�x86_64-darwin: 3,124,231 (4.93%)�java: 1,065,024 (1.68%)�x64-mingw32: 326,319 (0.51%)�arm64-darwin: 137,295 (0.22%)�x86-mingw32: 18,721 (0.03%)�x86-linux: 16,018 (0.03%)

Compare to vanilla ruby: 2,685,027 (4.23%)

126 of 154

Back-of-the-envelope Power Calculations

Intel(R) Core(TM) i7-1065G7 CPU�rated at 15W TDP

60_000_000 * 15W * 11s

= 2.75 MWh over 10 months

127 of 154

Back-of-the-envelope Power Calculations

2.75 MWh over 10 months is …�

a refrigerator running for the same amount of time.

128 of 154

Back-of-the-envelope Power Calculations

2.75 MWh over 10 months is …�

560 pounds of carbon emissions

(about half of just my one-way flight from Newark to Denver)

129 of 154

Back-of-the-envelope Power Calculations

2.75 MWh over 10 months is …�

Not much, I guess? I thought it would be more.

130 of 154

Back-of-the-envelope Time Calculations

Default dev configuration on a modern laptop taks 82s to install Nokogiri (not precompiled)

With 8 cores, it’s 48s

131 of 154

Back-of-the-envelope Time Calculations

If even 10% of installations are humans (and not automated CI/CD),�that’s ~$13M USD in saved human labor.

(But even CI/CD has humans waiting for it sometimes, right?)

132 of 154

Precompiled Nokogiri is a Good Thing™

  • Fewer support issues opened
  • Fewer installation doc page hits (in a regime of increasing overall page hits)
  • Fewer angry tweets
  • I don’t feel bad about my second refrigerator anymore
  • A productivity gift to a lot of Ruby shops

133 of 154

A word about Trust

134 of 154

What’s in the box?

135 of 154

136 of 154

137 of 154

138 of 154

Why should you trust what’s in the box?

139 of 154

Do you trust the source

(the author)?

Do you trust the chain of custody�(the delivery system)?

140 of 154

Why do you trust this guy?�

Does he follow basic security hygiene?

Is he liable to be blackmailed?

Does He have illegal Gambling Debts?

141 of 154

You can trust this guy!

I’ve been around for a while

I have a history of shipping Nokogiri

You have met me in person, probably

Don’t worry, IMMAGOODGUY!

142 of 154

Why do you trust the supply chain?�

Have the maintainers all enabled MFA?

Was the gem signed?�Did you check the signature?�OR: did you verify checksums?

143 of 154

Probably, trust the supply chain? 😎�

Nokogiri maintainers use MFA!

Opted into new “MFA Required” feature!

Checksums always provided!

144 of 154

145 of 154

I think you are all too trusting,

And I just want you to be a little more paranoid

146 of 154

Multi-Factor Authentication

MFA makes it hard to impersonate you

  • Gem authors: enable MFA on rubygems.org, please!
  • New feature: gems can “opt in” to requiring MFA for all future versions.

147 of 154

Gem Signing

Gem signing and verification is wonky and very few people do it.

  • Let’s improve it!
  • Let’s try modern signature tech (like sigstore)

Find me and I will talk to you about this!

148 of 154

Coming Soon!

149 of 154

rake-compiler-dock

Support for ARM64 Linux!

150 of 154

rake-compiler-dock

Easier use in CI/CD pipelines!

151 of 154

rake-compiler-dock

Ship 3.1 support early this year? Maybe?�(Hi, Lars!)

152 of 154

Musl vs glibc

This is a pretty big problem.

153 of 154

Thank you!�

  • Lars Kanis
  • Luis Lavena
  • Kouhei Sutou�

154 of 154

Q&A