123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- = Why rake?
- Ok, let me state from the beginning that I never intended to write this
- code. I'm not convinced it is useful, and I'm not convinced anyone
- would even be interested in it. All I can say is that Why's onion truck
- must by been passing through the Ohio valley.
- What am I talking about? ... A Ruby version of Make.
- See, I can sense you cringing already, and I agree. The world certainly
- doesn't need yet another reworking of the "make" program. I mean, we
- already have "ant". Isn't that enough?
- It started yesterday. I was helping a coworker fix a problem in one of
- the Makefiles we use in our project. Not a particularly tough problem,
- but during the course of the conversation I began lamenting some of the
- shortcomings of make. In particular, in one of my makefiles I wanted to
- determine the name of a file dynamically and had to resort to some
- simple scripting (in Ruby) to make it work. "Wouldn't it be nice if you
- could just use Ruby inside a Makefile" I said.
- My coworker (a recent convert to Ruby) agreed, but wondered what it
- would look like. So I sketched the following on the whiteboard...
- "What if you could specify the make tasks in Ruby, like this ..."
- task "build" do
- java_compile(...args, etc ...)
- end
- "The task function would register "build" as a target to be made,
- and the block would be the action executed whenever the build
- system determined that it was time to do the build target."
- We agreed that would be cool, but writing make from scratch would be WAY
- too much work. And that was the end of that!
- ... Except I couldn't get the thought out of my head. What exactly
- would be needed to make the about syntax work as a make file? Hmmm, you
- would need to register the tasks, you need some way of specifying
- dependencies between tasks, and some way of kicking off the process.
- Hey! What if we did ... and fifteen minutes later I had a working
- prototype of Ruby make, complete with dependencies and actions.
- I showed the code to my coworker and we had a good laugh. It was just
- about a page worth of code that reproduced an amazing amount of the
- functionality of make. We were both truly stunned with the power of
- Ruby.
- But it didn't do everything make did. In particular, it didn't have
- timestamp based file dependencies (where a file is rebuilt if any of its
- prerequisite files have a later timestamp). Obviously THAT would be a
- pain to add and so Ruby Make would remain an interesting experiment.
- ... Except as I walked back to my desk, I started thinking about what
- file based dependencies would really need. Rats! I was hooked again,
- and by adding a new class and two new methods, file/timestamp
- dependencies were implemented.
- Ok, now I was really hooked. Last night (during CSI!) I massaged the
- code and cleaned it up a bit. The result is a bare-bones replacement
- for make in exactly 100 lines of code.
- For the curious, you can see it at ...
- * doc/proto_rake.rdoc
- Oh, about the name. When I wrote the example Ruby Make task on my
- whiteboard, my coworker exclaimed "Oh! I have the perfect name: Rake ...
- Get it? Ruby-Make. Rake!" He said he envisioned the tasks as leaves
- and Rake would clean them up ... or something like that. Anyways, the
- name stuck.
- Some quick examples ...
- A simple task to delete backup files ...
- task :clean do
- Dir['*~'].each {|fn| rm fn rescue nil}
- end
- Note that task names are symbols (they are slightly easier to type
- than quoted strings ... but you may use quoted string if you would
- rather). Rake makes the methods of the FileUtils module directly
- available, so we take advantage of the <tt>rm</tt> command. Also note
- the use of "rescue nil" to trap and ignore errors in the <tt>rm</tt>
- command.
- To run it, just type "rake clean". Rake will automatically find a
- Rakefile in the current directory (or above!) and will invoke the
- targets named on the command line. If there are no targets explicitly
- named, rake will invoke the task "default".
- Here's another task with dependencies ...
- task :clobber => [:clean] do
- rm_r "tempdir"
- end
- Task :clobber depends upon task :clean, so :clean will be run before
- :clobber is executed.
- Files are specified by using the "file" command. It is similar to the
- task command, except that the task name represents a file, and the task
- will be run only if the file doesn't exist, or if its modification time
- is earlier than any of its prerequisites.
- Here is a file based dependency that will compile "hello.cc" to
- "hello.o".
- file "hello.cc"
- file "hello.o" => ["hello.cc"] do |t|
- srcfile = t.name.sub(/\.o$/, ".cc")
- sh %{g++ #{srcfile} -c -o #{t.name}}
- end
- I normally specify file tasks with string (rather than symbols). Some
- file names can't be represented by symbols. Plus it makes the
- distinction between them more clear to the casual reader.
- Currently writing a task for each and every file in the project would be
- tedious at best. I envision a set of libraries to make this job
- easier. For instance, perhaps something like this ...
- require 'rake/ctools'
- Dir['*.c'].each do |fn|
- c_source_file(fn)
- end
- where "c_source_file" will create all the tasks need to compile all the
- C source files in a directory. Any number of useful libraries could be
- created for rake.
- That's it. There's no documentation (other than whats in this
- message). Does this sound interesting to anyone? If so, I'll continue
- to clean it up and write it up and publish it on RAA. Otherwise, I'll
- leave it as an interesting exercise and a tribute to the power of Ruby.
- Why /might/ rake be interesting to Ruby programmers. I don't know,
- perhaps ...
- * No weird make syntax (only weird Ruby syntax :-)
- * No need to edit or read XML (a la ant)
- * Platform independent build scripts.
- * Will run anywhere Ruby exists, so no need to have "make" installed.
- If you stay away from the "sys" command and use things like
- 'ftools', you can have a perfectly platform independent
- build script. Also rake is only 100 lines of code, so it can
- easily be packaged along with the rest of your code.
- So ... Sorry for the long rambling message. Like I said, I never
- intended to write this code at all.
|