From: Jim Weirich Date: 2005-04-28T11:47:19+09:00 Subject: Re: Rake help required On Wednesday 27 April 2005 07:38 pm, Mark Probert wrote: > Hi .. > > I am not sure how to create a set of Rake rules to do the following. Can > anyone prove assistance? I think the following Rakefile will do what you want. I added extensive comments to the file rather than do commentary in this message. Let me know if you have problems. -- Rakefile ---------------------------------------------------------------- require 'rake/clean' # Create some constants for later reference. PROG = "foo" LIBNAME = PROG LIBFILE = "lib#{LIBNAME}.a" # For SRC, we just find all files in the project ending in '.c'. This # will work with nested source directories too (like might be found in # a Java project). SRC = FileList['**/*.c'] # Generate the OBJ list by striping off the directory portion of the # source file name and flattening the names into a single level obj # directory. This assumes that all the base file names are unique, # but that is given by the problem statement. (Note that the +ext+ # function is available in Rake 0.5.3 or later). OBJDIR = 'obj' OBJ = SRC.collect { |fn| File.join(OBJDIR, File.basename(fn).ext('o')) } # Define our clean and clobber targets. CLEAN.include(OBJ, OBJDIR, LIBFILE) CLOBBER.include(PROG) # The default task builds, then runs the program task :default => [:build, :run] # The build task just depends upon the program being present. task :build => [PROG] # The run task requires the program to be present, and then runs that # program. task :run => [PROG] do sh "./#{PROG}" end # The program depends only on the library file. file PROG => [LIBFILE] do sh "cc -o #{PROG} -L . -l#{LIBNAME}" end # The library file depends only on the list of objects we constructed # at the top of the file. file LIBFILE => OBJ do sh "ar cr #{LIBFILE} #{OBJ}" sh "ranlib #{LIBFILE}" end # The directory directive defines the directory OBJDIR as a task that # can be used in a prerequisites list in a task declaration. directory OBJDIR # Ok, this is the tricky part. This rule generates .o files from a # source file described by a lambda function. Finding the source file # is tricky because the object file does not indicate /which/ source # directory contains the matching .c file. We punt by writing a # special function to locate the source. (Originally I did this # inline in the lambda, but I think it reads better split out into a # separate functions). # # Note that we invoke the OBJDIR task directly in this rule. Because # it is a rule, there is no opportunity to list OBJDIR as a # dependency. By invoking it directly, we will build that directory # if it is needed (but only if it is needed). rule '.o' => lambda{ |objfile| find_source(objfile) } do |t| Task[OBJDIR].invoke sh "cc -c -o #{t.name} #{t.source}" end # It turns out that finding the source file is not that difficult. We # just search the list of source files for a match on the basename of # the object file. Obviously this might have a performance problem # with a _large_ list of source files. In that case, I would build a # hash at the top of the Rakefile and use that hash here when looking # up the source. def find_source(objfile) base = File.basename(objfile, '.o') SRC.find { |s| File.basename(s, '.c') == base } end ----------------------------------------------------------------- -- -- Jim Weirich jim@weirichhouse.org http://onestepback.org ----------------------------------------------------------------- "Beware of bugs in the above code; I have only proved it correct, not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)