Rake help required

M

Mark Probert

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,
 
S

Stefan Lang

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, :eek: => 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
 
J

Jim Weirich

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
 
S

Saynatkari

Le 28/4/2005 said:
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
 
M

Mark Probert

Hi ..

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,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

[ANN] Rant 0.3.6 0
rake help 5
ANN: Rake 0.8.4 Released 2
rake aborted! -- Help 3
Rake 0.8.7 needs Ruby 1.8? 4
Problem with rake and dependencies 5
rake test help 2
[ANN] Rake 0.8.2 Released 0

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top