Rake::Builder

Posted by Joe Yates Sat, 28 Aug 2010 23:42:00 GMT

I've put together a rake-based system for building C and C++ projects.

I've called it Rake::Builder, it's available on GitHub here.

autoconf

Build systems are complicated by external dependencies: finding third-party headers and libraries. Often there is a specific configuration for each operating system and distribution.

The standard system is GNU's autoconf system, but it is a nightmare. At the most simple level, you distribute source code with a Makefile.
The problem is that Makefiles are just pure dependency managers - if they don't find what they need, they just fail.
The solution to that problem is the use of configure. Configure runs a series of compatibility tests, sniffs the host system and spits out a Makefile.
So, with configure, the user then does the following:

$ ./configure
$ make
$ sudo make install

But, configure itself is a long file, and it's is a program: about 6000 lines of shell code.
A few lines:

ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
The solution to having to maintain configure? Generate it!
With autotools, there is a seemingly eternal regress of configuration files and scripts generated by other scripts.
This was my project's root directory listing before I gave up on autoconf:
AUTHORS
COPYING
ChangeLog
EXAMPLE
INSTALL
Makefile
Makefile.am
Makefile.in
NEWS
README
aclocal.m4
autom4te.cache
config.h
config.h.in
config.log
config.status
configure
configure.ac
depcomp
include
install-sh
missing
objects
src
stamp-h1
test
Fifteen of those files are involved in the mechanics of autoconf.

Autoconf doesn't really address the issue of building on various systems and adapting semi-automatically. You still have to add all the settings, but you have to learn where in a myriad of files these settings are to be placed.

Rake

Of the autoconf alternatives, rake seems to offer the cleanest solution. Rake itself was apparently created as a build system for C, but out of the box it's too generic: it's simply a dependency handling system.

There are already a number of specializations of rake. In Rails projects, and Gem building, Rakefiles handle maintenance, testing, documentation building and packaging.
This is the Gem building part of Rake::Builder's own Rakefile:

spec = Gem::Specification.new do |s|
  s.name             = 'rake-builder'
  s.summary          = 'Rake for C/C++ Projects'
  s.description      = 'Provides Rake:Builder, a specific rake TaskLib for building C, C++, Objective-C and Objective-C++ projects'
  s.version          = Rake::Builder::VERSION::STRING

  s.homepage         = 'http://github.com/joeyates/rake-builder'
  s.author           = 'My Name'
  s.email            = 'my.email@xmail.com'

  s.files            = ADMIN_FILES +
                       SOURCE_FILES +
                       EXAMPLE_SOURCE_FILES +
                       EXAMPLE_EXTRA_FILES
  s.require_paths    = [ 'lib' ]
  s.add_dependency( 'rake', '>= 0.8.7' )

  s.has_rdoc         = true
  s.rdoc_options     += RDOC_OPTS
  s.extra_rdoc_files = RDOC_FILES

  s.test_files       = SPEC_FILES
end

Rake::Builder is my attempt to specialise rake to the task of building C and C++ projects.
I've got to version 0.0.11 and it now builds the following types of projects:

  • C++,
  • QT C++,
  • C
  • Objective-C

This is an example with two build targets: a static library and a test executable, with the test project depending on the library:

require 'rake/builder'

Rake::Builder.new do |builder|
  builder.target               = 'libactive_record_sqlite.a'
  builder.source_search_paths  = [ 'src' ]
  builder.header_search_paths  = [ 'include/**/*.h' ]
  builder.objects_path         = 'objects'
  builder.include_paths        = [ 'include' ]
  builder.library_dependencies = [ 'sqlite3' ]
end

Rake::Builder.new do |builder|
  builder.task_namespace       = :test
  builder.target               = 'active_record_test'
  builder.source_search_paths  = [ 'test' ]
  builder.header_search_paths  = [ 'test' ]
  builder.objects_path         = 'test/lib_objects'
  builder.include_paths        = [ 'include', 'test' ]
  builder.library_dependencies = [ 'sqlite3', 'gtest', 'gtest_main', 'active_record_sqlite' ]
  builder.library_paths        = [ 'objects' ]
  builder.target_prerequisites = [ :'rake:build' ]
  builder.default_task         = [ :run ]
end

I'm about to start using Rake::Builder on a sizable C++ project using QT, so I'll have a chance to see if it handles real world stuff without turning into autoconf.

Show your Git Branch Name in your GNU Screen Status Line

Posted by Joe Yates Tue, 09 Mar 2010 07:57:00 GMT

I think my shell prompt is already cluttered enough, so I decided to show my current git branch in my GNU Screen status line instead.

Debian Alternatives

Posted by Joe Yates Mon, 22 Feb 2010 22:57:00 GMT

Debian Alternatives is a powerful system which allows you to decide which out of many is the implementation of a certain program that you want to use. It also handles groups of programs which can be selected all together.

Setting up PostGIS

Posted by Joe Yates Mon, 22 Feb 2010 14:34:00 GMT

How to setup PostGIS in your PostgreSQL database.

Shared Git Repositories

Posted by Joe Yates Sun, 21 Feb 2010 22:06:00 GMT

When you want to have a central shared git repository to push commits to, there are two common configurations: 1. Everybody uses the same user for commits - easy to set up, but very messy, 2. Create a system user for each committer, create a system group for each project and add users to relevant groups. The post explains how to set up and manage configuration the second option.

Managing multiple GNU screen sessions

Posted by Joe Yates Mon, 01 Feb 2010 18:46:00 GMT

GNU screen lets you can have multiple persistent screen sessions, and reload them by name.

Callbacks in Objective-C

Posted by Joe Yates Sat, 30 Jan 2010 15:55:00 GMT

In Objective-C, callback functions are a bit of a mystery - if you search for the on Google you get the impression they can;t be done. In this article I provide a recipe for using them