CMake prototype for mruby

Update: my CMake prototype mentioned in this post has been accepted into the mainstream mruby codebase. You no longer need to use my prototype branch; original instructions have been modified appropriately.

With some help from @beoran and @bovi, I've turned a question about mruby build automation into a prototype that's almost ready to submit for review for inclusion into mruby. While a fair bit of work remains, the prototype is good enough that I'm pushing it out of the nest for further testing. I've used the prototype to successfully build mruby on the following 32bit systems:

And @bovi has successfully built mruby with CMake on OS X Lion using an earlier version of the prototype. Build success stories summarized here.

This post isn't a tutorial on CMake or how to embed mruby into another application, but rather, a jumpstart to get you up and running with a minimum amount of fuss.

Get Ready

There's only four requirements (OK, five if you count git) for building mruby using the CMake prototype:

  1. A working bison installation
  2. A GCC-based or Windows SDK 7.1 development toolchain
  3. A working CMake 2.8.8+ installation, and
  4. A local clone of the mruby repo.

For Windows hackers, the quickest way to get (1) and (2) is to download a self-extracting 32bit MSYS/MinGW 4.6.2 DevKit from TheCodeShop's Ruby downloads page. It's built from my RubyInstaller recipes and can be used standalone or integrated into one of your existing Rubies by following these instructions. If you're feeling edgy you can build your own DevKit by cloning the RubyInstaller repo and running my DevKit build recipe similar to rake devkit dkver=mingw64-32-4.7.1 sfx=1 from the root directory. Look in the pkg subdirectory for your freshly baked DevKit. Type rake devkit:ls to list the available DevKit flavors.

Builds using Windows SDK 7.1 and nmake compatible Makefiles generated by cmake -G "NMake Makefiles" .. also work.

For Unix-like and OS X hackers, life is much simpler as it's likely you have both (1) and (2) already installed on your system. If not, it's usually just a matter of eloquently conversing with your package manager. Something similar to sudo pacman -S gcc or sudo apt-get gcc. Sorry, I don't use OS X or speak MacPorts/Homebrew/Fink yet ;)

To install CMake 2.8.8+, Windows users should download and install a prebuilt binary. I extracted the archive into C:\Apps\cmake and created a cmakevars.bat helper to bring C:\Apps\cmake\bin onto my PATH rather than using the CMake installer. Unix-like users can speak nicely to their package manager, install the cmake-2.8.8-Linux-i386.tar.gz binary archive, or build CMake from source.

Finally, you need to clone the mruby GitHub source repository by doing something similar to the following. All examples will be shown on a Windows 7 system using an MSYS/MinGW toolchain.

C:\Users\Jon\Documents\RubyDev>git clone mruby-git
C:\Users\Jon\Documents\RubyDev>cd mruby-git

Next, smoke test the setup and make sure you're ready to build.

# ALWAYS build outside the source tree!...we'll use the default `build` subdir
C:\Users\Jon\Documents\RubyDev\mruby-git>cd build

# make the GCC toolchain and bison available for use
Adding the DevKit to PATH...

# ensure cmake is working
C:\Users\Jon\Documents\RubyDev\mruby-git\build>cmake --version
cmake version 2.8.8

Looks great. Time to see how CMake helps us build mruby.

Let's Go!

In this example, I'm overcomplicating things a bit by showing you how to instruct CMake to customize your build configuration by overriding CMake's CMAKE_C_COMPILER to use the clang compiler.

DO NOT use the sample command line as-is. On Windows systems use cmake -G "MSYS Makefiles .. to build with the DevKit's GCC. On Unix-like systems use cmake .. to build with the system GCC.

C:\Users\Jon\Documents\RubyDev\mruby-git\build>cmake -G "MSYS Makefiles" -DCMAKE_C_COMPILER=C:/clang/bin/clang.exe ..
-- The C compiler identification is Clang 3.1.0
-- Check for working C compiler: C:/clang/bin/clang.exe
-- Check for working C compiler: C:/clang/bin/clang.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Build type not set, defaulting to 'RelWithDebInfo'
-- Found BISON: C:/DevKit/bin/bison.exe (found version "2.4.2")
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/Jon/Documents/RubyDev/mruby-git/build

[  1%] [BISON][mruby] Building parser with bison 2.4.2
Scanning dependencies of target mruby_object

You should end up seeing colorful build messages scroll across your shell similar to the following:

CMake mruby build

Locally Install and Smoke Test

By default, CMake creates Makefiles that install the necessary mruby artifacts into your local mruby repo directory structure. Specifically, it installs the mrbc and mruby executables into bin, the static library libmruby.a into lib, and headers into include.

Nice, but how about we just install and smoke test mruby.exe by making it spit out a verbose hello mruby!?

C:\Users\Jon\Documents\RubyDev\mruby-git\build>make install
[ 87%] Built target mruby_object
[ 88%] Built target xpcat
[ 88%] Built target mruby_static
[ 90%] Built target mrbc
[ 98%] Built target mrblib_object
[ 98%] Built target libmruby_static
[100%] Built target mruby
Install the project...
-- Install configuration: "RelWithDebInfo"
-- Installing: C:/Users/Jon/Documents/RubyDev/mruby-git/lib/mruby.lib
-- Installing: C:/Users/Jon/Documents/RubyDev/mruby-git/bin/mrbc.exe
-- Installing: C:/Users/Jon/Documents/RubyDev/mruby-git/bin/mruby.exe

C:\Users\Jon\Documents\RubyDev\mruby-git\build>..\bin\mruby.exe -v -e "puts 'hello mruby!'"
ruby 1.8.7 (2010-08-16 patchlevel 302) [i386-mingw32]
  local variables:
      method='puts' (308)
        NODE_STR "hello mruby!" len 12
irep 115 nregs=4 nlocals=2 pools=1 syms=1
001 OP_STRING   R3      'hello mruby!'
003 OP_SEND     R2      'puts'  1

hello mruby!

The default install behavior can be modified when invoking cmake similar to cmake -G "MSYS Makefiles" -D CMAKE_INSTALL_PREFIX=C:/Devlibs/mruby ..

Because you built outside of the source tree in the build subdirectory, cleanup is as easy as deleting the build dir contents (except .gitkeep) via a rm -rf *.

That's a Wrap

What's that you say? You'd like all the goodies packaged up into *.tar.gz and *.zip's ready to distribute? Child's play.

C:\Users\Jon\Documents\RubyDev\mruby-git\build>make package
[ 87%] Built target mruby_object
[ 87%] Built target mruby_static
[ 88%] Built target mrbc
[ 90%] Built target xpcat
[ 98%] Built target mrblib_object
[ 98%] Built target libmruby_static
[100%] Built target mruby
Run CPack packaging tool...
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: MRUBY
CPack: - Install project: MRUBY
CPack: Create package
CPack: - package: C:/Users/Jon/Documents/RubyDev/mruby-git/build/mruby-0.1.1-win32.tar.gz generated.
CPack: Create package using ZIP
CPack: Install projects
CPack: - Run preinstall target for: MRUBY
CPack: - Install project: MRUBY
CPack: Create package
CPack: - package: C:/Users/Jon/Documents/RubyDev/mruby-git/build/ generated.

Things Left TODO


The CMake prototype, while not perfect, is solid enough to handle more testing in different build and runtime scenarios. Take it out for a spin and see how it works for you. If you discover problems, submit an issue. If you've got the time and interest, dive in and help fix one of the open issues that irritates you the most.

My goal is to refine the prototype just enough so that it reliably creates native builds on 32/64bit Windows (nmake, not MSVC IDE), Linux, and OS X systems. Once the prototype appears robust, I will bundle up the commits and submit a pull request for Matz to review.

If Matz agrees that a cross platform CMake build system adds value to mruby, further refinements and enhancements should happen as part of the official mruby repository rather than The CodeShop.

« Back