[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Rake help required

Mark Probert

4/27/2005 11:38:00 PM


Hi ..

I am not sure how to create a set of Rake rules to do the following. Can
anyone prove assistance?

Structure:

Rakefile
foo
src_a/
a_1.c
a_2.c
src_b/
b_1.c
b_2.c
obj/
a_1.o
a_2.o
b_1.o
b_2.o
libfoo.a ("ar cr libfoo.a obj/*.c; ranlib libfoo.a")

I would like to have a single target

$ rake build

That would create the .o and the lib, then link them into the executable. I
can do this if everything is in the root directory but I am finding defining
the objects trickier.

I'd rather avoid explicitly putting the directory name in the source list,
like

SRC_A = ["src_a/a_1.c" ...]

Regards,


--
-mark. (probertm at acm dot org)


4 Answers

Stefan Lang

4/28/2005 12:30:00 AM

0

On Thursday 28 April 2005 01:38, Mark Probert wrote:
> Hi ..
>
> I am not sure how to create a set of Rake rules to do the following. Can
> anyone prove assistance?
>
> Structure:
>
> Rakefile
> foo
> src_a/
> a_1.c
> a_2.c
> src_b/
> b_1.c
> b_2.c
> obj/
> a_1.o
> a_2.o
> b_1.o
> b_2.o
> libfoo.a ("ar cr libfoo.a obj/*.c; ranlib libfoo.a")
>
> I would like to have a single target
>
> $ rake build
>
> That would create the .o and the lib, then link them into the executable.
> I can do this if everything is in the root directory but I am finding
> defining the objects trickier.
>
> I'd rather avoid explicitly putting the directory name in the source list,
> like
>
> SRC_A = ["src_a/a_1.c" ...]
>
> Regards,

An Rantfile that does this job could look like:

desc "Build foo."
file :foo => "obj/libfoo.a" do |t|
# adjust...
sys "cc -o #{t.name} #{t.source}"
end

o_files = sys["**/*.c"].map { |f| "obj/" + File.basename(f).sub_ext("o") }
file "obj/libfoo.a" => o_files do |t|
sys "ar cr #{t.name} #{t.prerequisites.arglist}"
sys "ranlib #{t.name}"
end

o_to_c = lambda { |t|
t =~ /^obj\/([^_])_/
"src_#{$1}/#{File.basename(t)}".sub_ext "c"
}
gen Rule, :o => o_to_c do |t|
sys "cc -c -o #{t.name} #{t.source}"
end

When invoking rant it will build foo, as its the first task:
% rant

Stefan


Jim Weirich

4/28/2005 2:47:00 AM

0

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://onest...
-----------------------------------------------------------------
"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)


ES

4/28/2005 3:26:00 AM

0


Le 28/4/2005, "Jim Weirich" <jim@weirichhouse.org> a écrit:
>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
>-----------------------------------------------------------------

This subfolder-sourcing seems like a common usage pattern,
perhaps worthy of some sort of an abstraction? Is there any
sort of a 'common Rake task idioms' collection anywhere?

>-- Jim Weirich

E

--
template<typename duck>
void quack(duck& d) { d.quack(); }



Mark Probert

4/28/2005 5:13:00 AM

0

Hi ..

On Wednesday 27 April 2005 19:47, Jim Weirich wrote:
> 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.
>
Many thanks, Jim.

Maybe I should start putting together a newbies guide to using Rake for C
development from the posts you have sent...

Regards,

--
-mark. (probertm at acm dot org)