Rake - a build system using code written in Ruby
Archive - Originally posted on "The Horse's Mouth" - 2011-02-03 05:28:52 - Graham EllisIf you're programming in C, C++ or Java, you'll be managing a large number of source files, and using a whole series of commands to build these forward into .o (object) or .class (java class) files, then - in the cases of C and C++ - into executable files.
The make system has been around for as long as I can remember for C (and Fortran and other) builds. It's very clever, but has some curiosities of syntax and its own definition language - and indeed, in the Java world, Apache Ant has been around for quite a while to provide an alternative. And indeed Ant and Make are used extensively for a very wide range of other build tasks these days - far beyond just building or preparing for executable files.
Rake is another build system. It's a Ruby application, and you write a rakefile - the file that describes what depends on what, and how to get from the source to the target of each stage of the process as a piece of Ruby. The rake program, which is written in Ruby, then goes through all the dependencies and builds the code when you run it.
Let's see an example:
file 'shape.o' => ["shape.c", "shape.h"] do
sh "gcc -c -o shape.o shape.c"
end
and that says "if shape.c or shape.h has changed since shape.o was last produced, run the following shell command". It checks the time and date stamps on the various files to see if the work needs to be done and (the clever bit) it will recursively check on the files shape.c and shape.h first to see if they need to be refreshed first, thus provoking a need for shape.o to be refreshed too even if at first glance it's up to date (i.e. newer than either of its dependencies).
By comparison, the same dependency written in a makefile looks like:
shape.o: shape.c shape.h
gcc -c -o shape.o shape.cpp
There's a complete rakefile example [here], and the equivalent makefile [here]. The application used in the example is from a recent C++ course ... a whole lot of source files, as it's my worked example of how you would split an application over a series of files with separate header and code files for each class. They are ... shape_main.cpp, square.cpp, square.h, rectangle.cpp, rectangle.h, circle.cpp, circle.h, shape.cpp and shape.h
To run rake, you'll run the rake command at the command line, which runs the ruby program, which in turn pulls in your instructions from the rakefile and does whatever's needed:
munchkin:c5 grahamellis$ rake hereitis
(in /Users/grahamellis/c5)
Compiling shape_main
Compiling shape
Compiling square
Compiling circle
Compiling rectangle
Loading
munchkin:c5 grahamellis$ rake hereitis
(in /Users/grahamellis/c5)
munchkin:c5 grahamellis$
So the first time I ran it, all the work had to be done ... the second time, everything was up to date and no compiling of my C++ program was necessary.
Further elements of rake allow you to specify general rules for everything of a particular type, and specify things like "all .h files in a directory" which means you can build up sets of rules with lots of file specified very quickly. And because you have ruby there too, you can write loops and other code to generate a whole lot of elements of your build tree in just a few lines. Although the single source-target example above was shorter in a makefile, typically a rakefile as a whole will be much shorter, and easier to follow too if you knoe Ruby.
Rake is extensively used in Rails. Rails is the Ruby based web framework, and there's a whole range of things such as databases to be setup when you start, refreshed when you update your code and start a fresh set of tests, etc ... and rake is used for these tasks. You'll find that all the standard rake files used by rails when you start using it are there for you, but you may need to get in later. And if - as my customers are doing this week - you're using C++ as a production language and Ruby as your company's scripting standard, it's going to be logical for you to choose rake as your build tool. You can find the rake documentation [here], and about our Ruby courses [here].