[CMake] Re: Raven, Antwrap, Buildr

Gonzalo Garramuño ggarra at advancedsl.com.ar
Mon Mar 3 09:13:01 EST 2008


Brandon Van Every wrote:
> On Sun, Mar 2, 2008 at 7:46 PM, Brandon Van Every <bvanevery at gmail.com> wrote:
>> On Sun, Mar 2, 2008 at 7:29 PM, Brandon Van Every <bvanevery at gmail.com> wrote:
>>  >
>>  >  http://www.onjava.com/pub/a/onjava/2007/12/05/introducing-raven-an-elegant-build-for-java.html
>>
>>  The comments following this article are interesting.  For instance, on syntax:
>>
>>  "This is just stupid. The Ruby syntax is horrendous. I'd rather use
>>  Groovy than Ruby if I was ever going to use a scripting language. I've
>>  never been stuck using Ant either, it does everything I need."
> 

It is not the ruby syntax that is horrendous but the rake one.  I'm a 
true fan of ruby but not of rake.   Raven is just a wrapper built on top 
of rake to add java functionality.


> - is a :colon in front of something a great idea?

It is a pretty good one. It isn't of course as clean as just a simple 
string with no quotes, but then again, you otherwise get quickly in 
trouble with local vars.  CMake basically does not have local vars (all 
are globals) and those are always defined/dealt in SET() commands.

 > - why do I have to type |bars| around something?

This is a ruby convention that is somewhat overused in rake.  The  do 
|iter| ... end   or   { |iter| ... }   defines a block with a local 
variable to the block which is usually used for iteration or for 
construction.

The local variable is usually filled by the caller (usually providing 
you with access to *this or self of the object you built).

The advantage is for OO.  Consider this:

task :myexe { |t|
       t.link_libs = "asdasd"
       t.so_version = 1.0
       t.call_func
}

With that, you'd basically have an OO approach to setting cmake 
properties (and not just properties, you can also run a function defined 
in whatever class t is).

That code is somewhat sugar akin to:

t = Rake::Task.new( "myexe" )
t.link_libs = 'asdasd'
t.so_version = 1.0
t.call_func

The benefit of not using the constructor directly is that the api is 
easier to change.  Also, at the end of the block (end or end bracket), a 
lot of other internal hidden code may run (for example, validating 
dependencies or parameters right away)-


>  From other context
> I read, it seems to be a decorator for a symbol.  So I guess if you
> forgot the decorator, you'd be in trouble.  I hope that always throws
> an intelligible error.

If your forget the decorator, it is interpreted as a local variable.  As 
no such variable would likely exist, you'd get an error.

Obviously this flexibility does allow you do, for example:

	#
	# 3 targets, each with same dependency.
	#

	targets = [ :target1, :target2, :target3 ]
         targets.each { |name|
		task name { |t|
			t.dependencies = %w( dep1 dep2 dep3 )
		}
	}

Here the symbol is replaced with a local variable called 'name' which 
changes on each iteration.
		



> - why put both [square brackets] and {curly braces} around something?

[square brackets] is an array, {} is a hash.   In the example you 
posted, you have an array of hashes, which is as ugly as it can get.

> Is that so we can be terse about minimum versions?

No.  It is just that the api you posted seems to require an array of 
hashes.  Pretty ugly api, if you ask me.  Having a hash that contains 
arrays (or other hashes) is more common.


> - how, in any universe, could this possibly be preferable to
> add_dependencies(target dep1 dep2 dep3...) ?
> 

An api (say swig wrapped) that would be identical to cmake would look like;

add_dependency :target, :dep1, :dep2, :dep3

Here I am using symbols, but you could also make the api use strings 
(which forces to use quotes) or accept both (which is usually the case 
with ruby).

add_dependency "target", "dep1", "dep2", "dep3"

or (if you want to make it more explicit as rake):

add_dependency :target => %w( dep1 dep2 dep3 )

In a more extensible api that would use hashes for values, it would look 
like:

add_dependency :target, :dependencies => %w( dep1 dep2 dep3 )

or, like rake does, use an OO approach:

task :target { |t|
	t.dependencies = %w( dep1 dep2 dep3 )
}

In ruby it is pretty trivial to provide both types of interfaces (even 
with swig for C++ code).  Rake only provides an OO api.


> Only Ruby people are going to see this syntax as an advantage.  It's
> worth remembering that Ruby got popular not because of the language,

No, ruby got popular with the language and is highly respected for it. 
Rails made it popular for the web.

Talking about rails, rails uses another form of DSL, which is class based.

Basically, a cmake api based like rails would look more like:

	class MyExe < CMake::Executable

              dependencies %w( dep1 dep2 dep3 )

	     def compile
                  # optionally override CMake::Executable compile routine
              end
	end

A class DSL really does not make that much sense for a build system, but 
it is obviously great for actual coding the core of the system.


P.S.  BTW, rake is something like a 200 line script only, so it is 
extremely bare-bones.


-- 
Gonzalo Garramuño
ggarra at advancedsl.com.ar

AMD4400 - ASUS48N-E
GeForce7300GT
Xubuntu Gutsy


More information about the CMake mailing list