The best kittens, technology, and video games blog in the world.

Tuesday, August 01, 2006

From make to rake

Photo from Commons by Felipe Micaroni Lalli, CC-BY-SA.
rake is a Ruby equivalent of make and it's much more cool. Some problems with make:
  • It is almost standard but not quite - some systems like Solaris use some broken non-GNU make (you need to use gmake there, bah). And without GNU extensions it's really hard to do many useful things with it.
  • Complex Makefiles are very fragile, for example changing order of entries has highly unpredictable effects.
  • It's really hard to do any non-trivial processing with make. What one really does is writing scripts that generate Makefiles, and then the Makefiles call even other scripts. Having everything in a single Rakefile is much nicer.
  • With Rakefile I can program in Ruby. Perl or Python would also work great with this kind of programs. Shell definitely does not.
  • Embedding Perl/Ruby one-liners in Makefile really sucks. I need to escape extra characters to protect against make, then to protect against shell. In the end I simply move everything to a different file.
So here's how RLisp's Rakefile looks like:
# Build the package using ANTLR
task :default do
 system "java -classpath lib/antlr-2.7.5.jar:lib/antlr-3.0ea7.jar:lib/stringtemplate-2.3b4.jar org.antlr.Tool RLispGrammar.g"
end

# Build first if packaging is requested
task :package => :default do
 date_string = Time.new.gmtime.strftime("%Y-%m-%d-%H-%M")
 files = %w[COPYING README STYLE
   antlr.rb RLispGrammar.g
   RLispGrammarLexer.rb RLispGrammar.rb
   rlisp.rb Rakefile
   rlisp_stdlib.rb stdlib.rl] +
   Dir.glob("examples/*.rl") +
   Dir.glob("examples/*.rb") +
   Dir.glob("lib/*.jar")

 # Prepend rlisp/ and temporarily chdir out
 # That's the only way to work with tar
 files = files.map{|f| "rlisp/#{f}"}
 Dir.chdir("..") {
   # Make a tarball
   system "tar", "-z", "-c", "-f", "rlisp/rlisp-#{date_string}.tar.gz", *files
   # and a zipball
   system "zip", "rlisp/rlisp-#{date_string}.zip", *files
 }
end

# Cleaning up
task :clean do
 generated_files = %w[
   RLispGrammarLexer.tokens
   RLispGrammarLexer.rb
   RLispGrammar.rb
   RLispGrammar.tokens
   RLispGrammar.lexer.g]
 generated_files.each{|file| File.delete(file)}
end
The packaging is way more cool that the one I did with Makefile. So the plan is to port all my programs (mainly jrpg which has fairly complex make system) to Rakefile. Well at least those that aren't using OCamlMake or ant or something like that. Score for Ruby :-)

No comments: