Lots of good resources into how we can build Ruby in Koichi’s Ruby Hack challenge.
A previous version of this page advocated for splitting the Ruby working tree into several different directories, one for source code, one for build artifacts and one for installed binaries in the same way as the Ruby hack challenge does. Personally, I found this too complex to work with on a day to day basis, preferring instead to just push everything into the same directory.
Here are some pros and cons I’ve found of using a unified build directory:
./configurein the wrong directory by accident!
make cleandoesn’t clean up everything you expect it to and subsequent compilations don’t give the results you expect.
Realistically there isn’t much in it. I don’t like configuring editors all that
much so the pros of a single tree outweigh the cons for me. And I’ve found that
the main con can be easily worked around with the liberal use of
git clean -fdx
Simples: for me this looks like this…
cd src git clone email@example.com/ruby/ruby.git cd ruby
autoconfit’s too low level and may not always do what you expect. Instead either use
autoreconf --install(which is basically what
autogenand some of the other
./configure --enable-shared --with-openssl-dir="$(brew --prefix openssl)" --with-readline-dir="$(brew --prefix readline)" --disable-libedit
Aaron recommended doing:
begin set -lx debugflags '-g' set -lx optflags '-O0' set -lx RUBY_DEVEL 'yes' ./configure --prefix=~../install --disable-install-doc --with-openssl-dir=(brew --prefix)/opt/openssl end
This is Fish shell syntax, which is what I use. YMMV
for other shells but you may be able to get away with swapping the
This will make sure that every time Ruby builds either itself or any of the included gems it always builds with:
-ginclude debug symbols - needed for C function labelling and decent debugger context (otherwise
lldbjust shows you assembly). You can
-O0minimal optimisations - this is needed to make sure that
cmakedoesn’t optimise out any local variables or useful information that you can use while debugging.
RUBY_DEVELenabled - I don’t actually know what this does yet.
--enable-sharedhas been removed. Omitting this flag will mean that Ruby gets built as one big statically linked binary instead of a small binary and a larger shared library. This makes debugging easier because it will make following code through the stacktrace easier. Make sure to enable shared libraries when doing benchmarking, as this is how Ruby is compiled for release builds.
It’s also possible to compile without this and then edit the generated
Makefile, but this doesn’t apply these to any gems that are built - just the
ruby binaries. Which can be a pain.
configure commands are for building on a Mac where we have to
workaround the Apple/Homebrew OpenSSL situation. These days I do almost all of
my dev on a Linux box where you can omit the
Generally I alias the snippet above to a function in fish shell so I can have different combinations of compile flags and install targets for different branches.
Here is the function I use to configure a default development version, when I want as near to standard settings as possible (but making debugging easier).
function configure-main set -lx debugflags '-ggdb3' set -lx optflags '-O0' set -lx RUBY_DEVEL 'yes' ./configure --prefix=$HOME/.rbenv/versions/main --disable-install-doc end
I am working on a feature that requires some extra build flags, so I use a seperate command to build for that case
function configure-rvargc set -lx debugflags '-ggdb3' set -lx optflags '-O0' set -lx RUBY_DEVEL 'yes' set -lx cflags '-DUSE_RVARGC=1' ./configure --prefix=$HOME/.rbenv/versions/rvargc --disable-install-doc end
Note the different
prefix locations, so I can
make install and switch
between two rubies that are built identically other than the presence of my
First find out how many working cpu’s you’ve got
On Linux that’s done with
~/src/ruby master ≡ mattvh@deunan ❯ nproc --all 12
on a Mac you can use
~/src/ruby master ≡ mattvh@kyouko ❯ sysctl -n hw.activecpu 12
A good general rule of thumb is to tell make to use
cpu_count + 1 threads
-j flag. You can run
make -j without a specific number but I
don’t because it can make things slower. Here’s a quote from Managing Projects
with GNU Make 3rd Edition
--jobsoption can be used without a number. If so, make will spawn as many jobs as there are targets to be updated. This is usually a bad idea, because a large number of jobs will usually swamp a processor and can run much slower than even a single job.
Then build Ruby and install it to your prefix:
make -j13 && make install
This will build and install
bundler et al and dump them
in your configured install directory. This takes time (rougly 5 minutes on my
work MacBook Pro, longer on my personal Surface Pro).
maketargets that are useful
make miniruby- Useful when you just need core ruby, doesn’t build gems or stdlib, you can’t use
requirebut it’s really fast so useful for a quick feedback loop. I use this all the time when working on GC stuff.
make- the default target, builds
make prepare-gems- installs the default set of gems that are built with ruby into the current build path (running the full test suite requires this)
make clean- cleans up all the build artifacts. Use this when making changes to configure flags that affect the core binaries. This doesn’t clean up the
./configurescript itself, or any artifacts created by
configure, so you can just
makeagain to build from scratch
make distclean- cleans up all artifacts created by configure and by make. if you get into an odd situation with build flags or weird
makebehaviour, generally this is a good way out. You’ll need to
./configureagain because this will clean up the generated
Once Ruby/miniruby is built you should be good to start development. See