Where I work, we use Rake as our main build tool.

Large parts of our system are written in C++, and we have some components that consist of several separate C++ projects that are related to each other. We are careful to follow the Acyclic Dependency Principle, but we’d still like to be able to build the whole family of projects together and in the correct order.

I recently helped a co-worker simplify this process, and I thought our solution was worth sharing. It’s a pretty simple idea, but it requires a mental shift from “Rake is just a build DSL” to “Rake is Ruby”.

We use gitslave to create a master project that includes all of the sub-projects. We then create a top-level Rakefile in the master project.

The basic idea is that we have a set of related projects that must be built in some order, and we have a common set of Rake tasks that we’d like to run on each of the projects.

Rakefile
PROJECTS = %w{child parent1 parent2 grandparent}
def iterating_task(*task_names)
task_names.each do |task_name|
task task_name do
iterate task_name
end
end
end
iterating_task :default, :build, :test, :clean, :clobber, :deploy
def iterate(task_name)
PROJECTS.each do |project|
Dir.chdir(project) do
puts "Running `rake #{task_name}' in #{p}"
sh "rake #{task_name}"
end
end
end

I’d love to move iterating_task down to the bottom of the file, but it needs to be defined before use.

With this Rakefile in place, we can run something like rake test in the master project, and will iterate through all of the projects in order and run their tests.

There’s more we could do with this, but it works well enough for now.