Packing your Ruby
application into a single
executable
Minqi Pan
Slide 2
Slide 2 text
I’m Minqi Pan
Slide 3
Slide 3 text
Beijing
Slide 4
Slide 4 text
Hacker of Ruby/C++
Slide 5
Slide 5 text
Node.js Collaborator
Slide 6
Slide 6 text
No content
Slide 7
Slide 7 text
github.com/pmq20
twitter
@psvr
Slide 8
Slide 8 text
No content
Slide 9
Slide 9 text
go build yours.go
Slide 10
Slide 10 text
No content
Slide 11
Slide 11 text
No content
Slide 12
Slide 12 text
Before
Slide 13
Slide 13 text
No content
Slide 14
Slide 14 text
No content
Slide 15
Slide 15 text
No content
Slide 16
Slide 16 text
No content
Slide 17
Slide 17 text
No content
Slide 18
Slide 18 text
No content
Slide 19
Slide 19 text
No content
Slide 20
Slide 20 text
Problems
• Slow installation. Tons of files to download. Great-
Wall’d in China. Remembered to use sudo?
• Error-prone. Failed compiling native modules?
Should I care about post-installations notices?
• Ruby runtime version? Wanted to use lonely
operator reliably? Coexist with multiple Rubies?
Slide 21
Slide 21 text
Updating?
Slide 22
Slide 22 text
No content
Slide 23
Slide 23 text
No content
Slide 24
Slide 24 text
No content
Slide 25
Slide 25 text
No content
Slide 26
Slide 26 text
No content
Slide 27
Slide 27 text
Problems
• No version checks. New versions missed without
your attentions.
• Cumbersome to update. Multiple steps needed.
Slide 28
Slide 28 text
After
Slide 29
Slide 29 text
No content
Slide 30
Slide 30 text
No content
Slide 31
Slide 31 text
No content
Slide 32
Slide 32 text
No content
Slide 33
Slide 33 text
Updating?
Slide 34
Slide 34 text
No content
Slide 35
Slide 35 text
No content
Slide 36
Slide 36 text
No content
Slide 37
Slide 37 text
Introducing
Slide 38
Slide 38 text
github.com/pmq20/
ruby-packer
Slide 39
Slide 39 text
enclose.io/rubyc
Slide 40
Slide 40 text
No content
Slide 41
Slide 41 text
Example 1. Producing a single
Ruby interpreter executable
Slide 42
Slide 42 text
Example 1. Producing a single
Ruby interpreter executable
Dave Vasilevsky
github.com/vasi
Author of
squashfuse
Slide 81
Slide 81 text
Shengyuan Liu
github.com/SounderLiu
Co-author of
libsquash
Slide 82
Slide 82 text
Introducing SquashFS
Slide 83
Slide 83 text
SquashFS
• a compressed read-only file system
• used by the Live CD versions of Arch
Linux, Debian, Fedora, Gentoo, Mint,
Salix, Ubuntu
• used on OpenWrt and DD-WRT router
firmware
Slide 84
Slide 84 text
a project
148M
after squashing
16M
mksquashfs
Slide 85
Slide 85 text
SquashFS
• Introduced in 2009 with Linux 2.6.29
• File format very stabilized
• Unsquashfs and mksquashfs have win32 ports;
7-Zip on win32 also supports SquashFS
• Part of kernel; GPL Licensed
Slide 86
Slide 86 text
Introducing libsquash
Slide 87
Slide 87 text
https://github.com/pmq20/libsquash
libsquash
• MIT licensed
• 100% User-land Code
• Embeddable, 1 dep. only
• Compiles on 3 platforms, even
Windows XP with VC++ 2010
• Introduces VFD - virtual file
descriptor, intercepting
system calls unobtrusively
libsquash
Slide 88
Slide 88 text
API of libsquash
mirroring system calls
Slide 89
Slide 89 text
Virtual File Descriptor
generated by a duplicating file descriptor 0
Slide 90
Slide 90 text
https://github.com/pmq20/libsquash
libsquash
Slide 91
Slide 91 text
File Descriptors
generated by libsquash others
https://github.com/pmq20/libsquash
libsquash
Slide 92
Slide 92 text
Use libsquash unobtrusively
Just include a header and it’s done!
Slide 93
Slide 93 text
Use libsquash unobtrusively
Win32 API works as well
Slide 94
Slide 94 text
What about Native
Extensions?
Slide 95
Slide 95 text
What about Native
Extensions?
• Libsquash Intercepts dlopen(), LoadLibraryExW()
• Dynamic library files inside the pack are extracted
to temporary files
• dlopen / LoadLibraryExW redirects the request to
the temporary files
• temporary files are deleted on exit
Slide 96
Slide 96 text
What about Rails?
Slide 97
Slide 97 text
But what about Rails?
• SquashFS is read-only, so your project root is read-
only
• Rails creates tmp/ or log/ and writes to it, and tmp/
or log/ is in your project root
• Rails has config files in your project root
Slide 98
Slide 98 text
Solution: writable root
• redirect `mkdir()` inside the memfs to a temporary
directory
• redirect `open()` with `O_CREAT` inside the memfs
to a temporary directory
• redirect `CreateFileW()` with writing inside the
memfs to a temporary directory
• removes the temporary directory and files at exit
Windows
• SquashFS Tools 4.3
• Visual Studio 2015 Update 3, all editions including
the Community edition (remember to select
“Common Tools for Visual C++ 2015" feature
during installation).
• Ruby
Slide 118
Slide 118 text
macOS
• SquashFS Tools 4.3: brew install squashfs
• Xcode, You also need to install the Command Line
Tools via Xcode.
• Ruby
Slide 119
Slide 119 text
Linux
• SquashFS Tools 4.3: sudo yum install squashfs-
tools or sudo apt-get install squashfs-tools
• gcc or clang
• GNU Make
• Ruby
Slide 120
Slide 120 text
Tips
Slide 121
Slide 121 text
Use --tmpdir=/a/fixed/location
Slide 122
Slide 122 text
Use Windows
with a big Virtual Memory
Slide 123
Slide 123 text
Use older Linux, e.g. CentOS release 5.8
with gcc and g++ 4.8
(possibly from devtoolset-2 of slc5-devtoolset)
Slide 124
Slide 124 text
Use older Mac, e.g. Mac OS X 10.7 Lion
with Xcode 4.6.3
Slide 125
Slide 125 text
Check dependencies using
Dependency Walker, otool, ldd
before releasing
Slide 126
Slide 126 text
See Also
Slide 127
Slide 127 text
“Real” Compiling
KEVIN DEISZ @ RubyConf 2017
Compiling Ruby