[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

rake question

Joe Van Dyk

7/15/2005 6:56:00 AM

rule '.o' => ['.c'] do |t|
sh "cc #{t.source} -c -o #{t.name}"
end

But, when I change the .c source file, it doesn't get compiled again.
Why is that?

Example:

PowerBook:~/that_stuff/test1 joe$ ls
Rakefile another_test.h test.cpp
another_test.cpp main.cpp test.h

PowerBook:~/that_stuff/test1 joe$ cat Rakefile
require 'rake/clean'
CLEAN.include '*.o', 'test'
CPP_SOURCE = FileList['*.cpp']
OBJS = CPP_SOURCE.ext 'o'

task :default => :run
task :run => "test" do
sh "./test"
end
file "test" => OBJS do
sh "g++ -o test #{OBJS}"
end
rule '.o' => '.cpp' do |t|
sh "g++ -c -o #{t.name} #{t.source}"
end
CPP_SOURCE.each do |cpp|
headers = File.read(cpp).scan(/^#include "(.+)"/)
task cpp => headers
end

PowerBook:~/that_stuff/test1 joe$ rake
(in /Users/joe/that_stuff/test1)
g++ -c -o another_test.o another_test.cpp
g++ -c -o main.o main.cpp
g++ -c -o test.o test.cpp
g++ -o test another_test.o main.o test.o
/test
Whassup
what's up!


PowerBook:~/that_stuff/test1 joe$ touch main.cpp
PowerBook:~/that_stuff/test1 joe$ rake
(in /Users/joe/that_stuff/test1)
/test
Whassup
what's up!

It should've recompiled main.cpp and relinked everything, right?


9 Answers

Joe Van Dyk

7/15/2005 7:07:00 AM

0

On 7/14/05, Joe Van Dyk <joevandyk@gmail.com> wrote:
> rule '.o' => ['.c'] do |t|
> sh "cc #{t.source} -c -o #{t.name}"
> end
>
> But, when I change the .c source file, it doesn't get compiled again.
> Why is that?
>
> Example:
>
> PowerBook:~/that_stuff/test1 joe$ ls
> Rakefile another_test.h test.cpp
> another_test.cpp main.cpp test.h
>
> PowerBook:~/that_stuff/test1 joe$ cat Rakefile
> require 'rake/clean'
> CLEAN.include '*.o', 'test'
> CPP_SOURCE = FileList['*.cpp']
> OBJS = CPP_SOURCE.ext 'o'
>
> task :default => :run
> task :run => "test" do
> sh "./test"
> end
> file "test" => OBJS do
> sh "g++ -o test #{OBJS}"
> end
> rule '.o' => '.cpp' do |t|
> sh "g++ -c -o #{t.name} #{t.source}"
> end
> CPP_SOURCE.each do |cpp|
> headers = File.read(cpp).scan(/^#include "(.+)"/)
> task cpp => headers
> end
>
> PowerBook:~/that_stuff/test1 joe$ rake
> (in /Users/joe/that_stuff/test1)
> g++ -c -o another_test.o another_test.cpp
> g++ -c -o main.o main.cpp
> g++ -c -o test.o test.cpp
> g++ -o test another_test.o main.o test.o
> ./test
> Whassup
> what's up!
>
>
> PowerBook:~/that_stuff/test1 joe$ touch main.cpp
> PowerBook:~/that_stuff/test1 joe$ rake
> (in /Users/joe/that_stuff/test1)
> ./test
> Whassup
> what's up!
>
> It should've recompiled main.cpp and relinked everything, right?

When I comment out
> CPP_SOURCE.each do |cpp|
> headers = File.read(cpp).scan(/^#include "(.+)"/)
> task cpp => headers
> end

Then it works as expected. So, "task cpp => headers" is the culprit.
But I'm still not sure why it breaks everything else.


Joe Van Dyk

7/15/2005 7:37:00 AM

0

On 7/15/05, Joe Van Dyk <joevandyk@gmail.com> wrote:
> On 7/14/05, Joe Van Dyk <joevandyk@gmail.com> wrote:
> > rule '.o' => ['.c'] do |t|
> > sh "cc #{t.source} -c -o #{t.name}"
> > end
> >
> > But, when I change the .c source file, it doesn't get compiled again.
> > Why is that?
> >
> > Example:
> >
> > PowerBook:~/that_stuff/test1 joe$ ls
> > Rakefile another_test.h test.cpp
> > another_test.cpp main.cpp test.h
> >
> > PowerBook:~/that_stuff/test1 joe$ cat Rakefile
> > require 'rake/clean'
> > CLEAN.include '*.o', 'test'
> > CPP_SOURCE = FileList['*.cpp']
> > OBJS = CPP_SOURCE.ext 'o'
> >
> > task :default => :run
> > task :run => "test" do
> > sh "./test"
> > end
> > file "test" => OBJS do
> > sh "g++ -o test #{OBJS}"
> > end
> > rule '.o' => '.cpp' do |t|
> > sh "g++ -c -o #{t.name} #{t.source}"
> > end
> > CPP_SOURCE.each do |cpp|
> > headers = File.read(cpp).scan(/^#include "(.+)"/)
> > task cpp => headers
> > end
> >
> > PowerBook:~/that_stuff/test1 joe$ rake
> > (in /Users/joe/that_stuff/test1)
> > g++ -c -o another_test.o another_test.cpp
> > g++ -c -o main.o main.cpp
> > g++ -c -o test.o test.cpp
> > g++ -o test another_test.o main.o test.o
> > ./test
> > Whassup
> > what's up!
> >
> >
> > PowerBook:~/that_stuff/test1 joe$ touch main.cpp
> > PowerBook:~/that_stuff/test1 joe$ rake
> > (in /Users/joe/that_stuff/test1)
> > ./test
> > Whassup
> > what's up!
> >
> > It should've recompiled main.cpp and relinked everything, right?
>
> When I comment out
> > CPP_SOURCE.each do |cpp|
> > headers = File.read(cpp).scan(/^#include "(.+)"/)
> > task cpp => headers
> > end
>
> Then it works as expected. So, "task cpp => headers" is the culprit.
> But I'm still not sure why it breaks everything else.

(I hope it's clear what I'm trying to do. I'm trying to scan the
included header files and if the header files have been changed, I
want to recompile all source files that include those header files. I
tried using "file cpp => headers", but that didn't help either.)


Olaf Klischat

7/15/2005 12:11:00 PM

0

Joe Van Dyk <joevandyk@gmail.com> writes:

> On 7/14/05, Joe Van Dyk <joevandyk@gmail.com> wrote:
>> rule '.o' => ['.c'] do |t|
>> sh "cc #{t.source} -c -o #{t.name}"
>> end
>>
>> But, when I change the .c source file, it doesn't get compiled again.
>> Why is that?
>>
>> Example:
>>
>> PowerBook:~/that_stuff/test1 joe$ ls
>> Rakefile another_test.h test.cpp
>> another_test.cpp main.cpp test.h
>>
>> PowerBook:~/that_stuff/test1 joe$ cat Rakefile
>> require 'rake/clean'
>> CLEAN.include '*.o', 'test'
>> CPP_SOURCE = FileList['*.cpp']
>> OBJS = CPP_SOURCE.ext 'o'
>>
>> task :default => :run
>> task :run => "test" do
>> sh "./test"
>> end
>> file "test" => OBJS do
>> sh "g++ -o test #{OBJS}"
>> end
>> rule '.o' => '.cpp' do |t|
>> sh "g++ -c -o #{t.name} #{t.source}"
>> end
>> CPP_SOURCE.each do |cpp|
>> headers = File.read(cpp).scan(/^#include "(.+)"/)
>> task cpp => headers
>> end
>>
>> PowerBook:~/that_stuff/test1 joe$ rake
>> (in /Users/joe/that_stuff/test1)
>> g++ -c -o another_test.o another_test.cpp
>> g++ -c -o main.o main.cpp
>> g++ -c -o test.o test.cpp
>> g++ -o test another_test.o main.o test.o
>> ./test
>> Whassup
>> what's up!
>>
>>
>> PowerBook:~/that_stuff/test1 joe$ touch main.cpp
>> PowerBook:~/that_stuff/test1 joe$ rake
>> (in /Users/joe/that_stuff/test1)
>> ./test
>> Whassup
>> what's up!
>>
>> It should've recompiled main.cpp and relinked everything, right?
>
> When I comment out
>> CPP_SOURCE.each do |cpp|
>> headers = File.read(cpp).scan(/^#include "(.+)"/)
>> task cpp => headers
>> end
>
> Then it works as expected. So, "task cpp => headers" is the culprit.
> But I'm still not sure why it breaks everything else.

Well, AFAICS it happens to be the case that, when you have defined an
explicit task like foo.cpp, then rules matching the task name won't be
considered when computing the dependencies of the task. See Task.[] in
rake.rb for details -- given a task name, it just returns the task if
it is defined, without considering additional dependencies imposed by
rules matching the task's name.

This could be considered unfortunate behaviour or a bug :) A related
problem I had is that rules can only define a single prerequisite,
which seems like a quite arbitrary restriction to me.

Stefan Lang

7/15/2005 12:20:00 PM

0

On Friday 15 July 2005 09:06, Joe Van Dyk wrote:
> On 7/14/05, Joe Van Dyk <joevandyk@gmail.com> wrote:
[...]
> > Example:
> >
> > PowerBook:~/that_stuff/test1 joe$ ls
> > Rakefile another_test.h test.cpp
> > another_test.cpp main.cpp test.h
> >
> > PowerBook:~/that_stuff/test1 joe$ cat Rakefile
> > require 'rake/clean'
> > CLEAN.include '*.o', 'test'
> > CPP_SOURCE = FileList['*.cpp']
> > OBJS = CPP_SOURCE.ext 'o'
> >
> > task :default => :run
> > task :run => "test" do
> > sh "./test"
> > end
> > file "test" => OBJS do
> > sh "g++ -o test #{OBJS}"
> > end
> > rule '.o' => '.cpp' do |t|
> > sh "g++ -c -o #{t.name} #{t.source}"
> > end
> > CPP_SOURCE.each do |cpp|
> > headers = File.read(cpp).scan(/^#include "(.+)"/)
> > task cpp => headers
> > end
> >
> > PowerBook:~/that_stuff/test1 joe$ rake
> > (in /Users/joe/that_stuff/test1)
> > g++ -c -o another_test.o another_test.cpp
> > g++ -c -o main.o main.cpp
> > g++ -c -o test.o test.cpp
> > g++ -o test another_test.o main.o test.o
> > ./test
> > Whassup
> > what's up!
> >
> >
> > PowerBook:~/that_stuff/test1 joe$ touch main.cpp
> > PowerBook:~/that_stuff/test1 joe$ rake
> > (in /Users/joe/that_stuff/test1)
> > ./test
> > Whassup
> > what's up!
> >
> > It should've recompiled main.cpp and relinked everything, right?
>
> When I comment out
>
> > CPP_SOURCE.each do |cpp|
> > headers = File.read(cpp).scan(/^#include "(.+)"/)
> > task cpp => headers
> > end
>
> Then it works as expected. So, "task cpp => headers" is the culprit.
> But I'm still not sure why it breaks everything else.

Your logic should be correct. It works if i run it with Rant (with some
minor Rake->Rant translations). Don't know why it doesn't work with Rake.

I don't want to advertise but Rant can scan #includes for you:

import "c/dependencies", "autoclean"
CPP_SOURCE = sys['*.cpp']
OBJS = CPP_SOURCE.map { |f| f.sub_ext "o" }

task :run => "test" do
sys "./test"
end
gen C::Dependencies
gen Action do source "c_dependencies" end
file "test" => OBJS do
sys "g++ -o test #{OBJS.arglist}"
end
gen Rule, '.o' => '.cpp' do |t|
sys "g++ -c -o #{t.name} #{t.source}"
end
desc "Remove generated files."
gen AutoClean

--
Stefan


Joe Van Dyk

7/15/2005 8:23:00 PM

0

On 7/15/05, Olaf Klischat <klischat@cs.tu-berlin.de> wrote:
> Joe Van Dyk <joevandyk@gmail.com> writes:
>
> > On 7/14/05, Joe Van Dyk <joevandyk@gmail.com> wrote:
> >> rule '.o' => ['.c'] do |t|
> >> sh "cc #{t.source} -c -o #{t.name}"
> >> end
> >>
> >> But, when I change the .c source file, it doesn't get compiled again.
> >> Why is that?
> >>
> >> Example:
> >>
> >> PowerBook:~/that_stuff/test1 joe$ ls
> >> Rakefile another_test.h test.cpp
> >> another_test.cpp main.cpp test.h
> >>
> >> PowerBook:~/that_stuff/test1 joe$ cat Rakefile
> >> require 'rake/clean'
> >> CLEAN.include '*.o', 'test'
> >> CPP_SOURCE = FileList['*.cpp']
> >> OBJS = CPP_SOURCE.ext 'o'
> >>
> >> task :default => :run
> >> task :run => "test" do
> >> sh "./test"
> >> end
> >> file "test" => OBJS do
> >> sh "g++ -o test #{OBJS}"
> >> end
> >> rule '.o' => '.cpp' do |t|
> >> sh "g++ -c -o #{t.name} #{t.source}"
> >> end
> >> CPP_SOURCE.each do |cpp|
> >> headers = File.read(cpp).scan(/^#include "(.+)"/)
> >> task cpp => headers
> >> end
> >>
> >> PowerBook:~/that_stuff/test1 joe$ rake
> >> (in /Users/joe/that_stuff/test1)
> >> g++ -c -o another_test.o another_test.cpp
> >> g++ -c -o main.o main.cpp
> >> g++ -c -o test.o test.cpp
> >> g++ -o test another_test.o main.o test.o
> >> ./test
> >> Whassup
> >> what's up!
> >>
> >>
> >> PowerBook:~/that_stuff/test1 joe$ touch main.cpp
> >> PowerBook:~/that_stuff/test1 joe$ rake
> >> (in /Users/joe/that_stuff/test1)
> >> ./test
> >> Whassup
> >> what's up!
> >>
> >> It should've recompiled main.cpp and relinked everything, right?
> >
> > When I comment out
> >> CPP_SOURCE.each do |cpp|
> >> headers = File.read(cpp).scan(/^#include "(.+)"/)
> >> task cpp => headers
> >> end
> >
> > Then it works as expected. So, "task cpp => headers" is the culprit.
> > But I'm still not sure why it breaks everything else.
>
> Well, AFAICS it happens to be the case that, when you have defined an
> explicit task like foo.cpp, then rules matching the task name won't be
> considered when computing the dependencies of the task. See Task.[] in
> rake.rb for details -- given a task name, it just returns the task if
> it is defined, without considering additional dependencies imposed by
> rules matching the task's name.
>
> This could be considered unfortunate behaviour or a bug :) A related
> problem I had is that rules can only define a single prerequisite,
> which seems like a quite arbitrary restriction to me.

Hm. So, are there any work arounds, other than to rebuild the entire
thing when a .h file changes?

What I'm trying to do is become a better software developer. So, I've
got a couple C and C++ books. I want to do the examples in them. So
I'll have directories like
/
/c/
/c/problem_1_1/
/c/problem_1_2/
/c/problem_1_2/main.c
/c/problem_1_2/foo.c
/c/problem_1_2/foo.h
/c/problem_1_2/test_foo.c
/c++/


And so on. I want a Rake file that will go into the directory
structure, compile all the code, compile all the test code, and run
the tests. Then I want it to create syntax-highlighted webpages that
shows for each example the code and the output and the tests, and then
posts them to a website where I can get comments on them.

Perhaps I'll have separate build directories (so I can build and test
the code on Windows, Linux, FreeBSD, and OS X)..

So, I'm looking for help for that.

Thanks!
Joe


Joe Van Dyk

7/15/2005 8:25:00 PM

0

On 7/15/05, Joe Van Dyk <joevandyk@gmail.com> wrote:
> On 7/15/05, Olaf Klischat <klischat@cs.tu-berlin.de> wrote:
> > Joe Van Dyk <joevandyk@gmail.com> writes:
> >
> > > On 7/14/05, Joe Van Dyk <joevandyk@gmail.com> wrote:
> > >> rule '.o' => ['.c'] do |t|
> > >> sh "cc #{t.source} -c -o #{t.name}"
> > >> end
> > >>
> > >> But, when I change the .c source file, it doesn't get compiled again

Stefan Lang

7/16/2005 12:43:00 AM

0


Content-Type: Multipart/Mixed;
boundary="Boundary-00=_jhF2CSKE7a36NCB"
On Friday 15 July 2005 22:24, Joe Van Dyk wrote:
[...]
> > What I'm trying to do is become a better software developer. So, I've
> > got a couple C and C++ books. I want to do the examples in them. So
> > I'll have directories like
> > /
> > /c/
> > /c/problem_1_1/
> > /c/problem_1_2/
> > /c/problem_1_2/main.c
> > /c/problem_1_2/foo.c
> > /c/problem_1_2/foo.h
> > /c/problem_1_2/test_foo.c
> > /c++/
> >
> >
> > And so on. I want a Rake file that will go into the directory
> > structure, compile all the code, compile all the test code, and run
> > the tests. Then I want it to create syntax-highlighted webpages that
> > shows for each example the code and the output and the tests, and then
> > posts them to a website where I can get comments on them.
> >
> > Perhaps I'll have separate build directories (so I can build and test
> > the code on Windows, Linux, FreeBSD, and OS X)..
> >
> > So, I'm looking for help for that.
>
> And I haven't looked at Rant much, would it be better for my purposes?
> Rake and Rant are both general purpose build utilities, right?

Yes, but Rant can automatically determine the dependencies between
C/C++ sources files (by extracting #include statements) and it has
some support for multiple directories (i.e. more than one Rantfile).

Actually a good example. I came up with the following solution for Rant:

% ls
c c++ Rantfile rule.rf
% ls c
problem_1_1 template.rf
% ls c++
problem_1_1 template.rf

The main Rantfile in the root directory copies the c/template.rf Rantfile
into all c/problem_* directories and the c++/template.rf into all
c++/problem_* directories.

If you run rant in the root directory, it will compile all tests
and run them. To compile only, run rant with "build" as only argument.
During work on one of the exercises you can change into the c(++)/problem*
directory and run rant to only compile/run the current exercise.

The example is in the attachment. The only problem is, that the last
Rant release contains a bug with regards to the Rule/subdirectory
combination. If you want, I can send you my development version offlist.

--
Stefan

Joe Van Dyk

7/17/2005 12:28:00 AM

0

On 7/15/05, Stefan Lang <langstefan@gmx.at> wrote:
> On Friday 15 July 2005 22:24, Joe Van Dyk wrote:
> [...]
> > > What I'm trying to do is become a better software developer. So, I've
> > > got a couple C and C++ books. I want to do the examples in them. So
> > > I'll have directories like
> > > /
> > > /c/
> > > /c/problem_1_1/
> > > /c/problem_1_2/
> > > /c/problem_1_2/main.c
> > > /c/problem_1_2/foo.c
> > > /c/problem_1_2/foo.h
> > > /c/problem_1_2/test_foo.c
> > > /c++/
> > >
> > >
> > > And so on. I want a Rake file that will go into the directory
> > > structure, compile all the code, compile all the test code, and run
> > > the tests. Then I want it to create syntax-highlighted webpages that
> > > shows for each example the code and the output and the tests, and then
> > > posts them to a website where I can get comments on them.
> > >
> > > Perhaps I'll have separate build directories (so I can build and test
> > > the code on Windows, Linux, FreeBSD, and OS X)..
> > >
> > > So, I'm looking for help for that.
> >
> > And I haven't looked at Rant much, would it be better for my purposes?
> > Rake and Rant are both general purpose build utilities, right?
>
> Yes, but Rant can automatically determine the dependencies between
> C/C++ sources files (by extracting #include statements) and it has
> some support for multiple directories (i.e. more than one Rantfile).
>
> Actually a good example. I came up with the following solution for Rant:
>
> % ls
> c c++ Rantfile rule.rf
> % ls c
> problem_1_1 template.rf
> % ls c++
> problem_1_1 template.rf
>
> The main Rantfile in the root directory copies the c/template.rf Rantfile
> into all c/problem_* directories and the c++/template.rf into all
> c++/problem_* directories.
>
> If you run rant in the root directory, it will compile all tests
> and run them. To compile only, run rant with "build" as only argument.
> During work on one of the exercises you can change into the c(++)/problem*
> directory and run rant to only compile/run the current exercise.
>
> The example is in the attachment. The only problem is, that the last
> Rant release contains a bug with regards to the Rule/subdirectory
> combination. If you want, I can send you my development version offlist.

Yeah, when I run 'rant', I get:
rant: [ERROR] Name error when loading
`/home/joe/repos/joe/learning/c_cpp_exercises/c++/problem_1_1/Rantfile':
undefined method `sub_ext' for #<Rant::RacFileList:0x4026baf4>
/usr/lib/ruby/gems/1.8/gems/rant-0.4.0/lib/rant/rantsys.rb:122:in
`method_missing'
/home/joe/repos/joe/learning/c_cpp_exercises/c++/problem_1_1/Rantfile:13:in
`instance_eval'
/usr/lib/ruby/gems/1.8/gems/rant-0.4.0/lib/rant/rantlib.rb:1002:in
`instance_eval'
/usr/lib/ruby/gems/1.8/gems/rant-0.4.0/lib/rant/rantlib.rb:1002:in
`load_file'
/usr/lib/ruby/gems/1.8/gems/rant-0.4.0/lib/rant/rantlib.rb:686:in
`subdirs'

And so on. Would that be fixed in the development version?


Stefan Lang

7/17/2005 6:46:00 AM

0

On Sunday 17 July 2005 02:28, Joe Van Dyk wrote:
> On 7/15/05, Stefan Lang <langstefan@gmx.at> wrote:
> > On Friday 15 July 2005 22:24, Joe Van Dyk wrote:
> > The example is in the attachment. The only problem is, that the last
> > Rant release contains a bug with regards to the Rule/subdirectory
> > combination. If you want, I can send you my development version offlist.
>
> Yeah, when I run 'rant', I get:
> rant: [ERROR] Name error when loading
> `/home/joe/repos/joe/learning/c_cpp_exercises/c++/problem_1_1/Rantfile':
> undefined method `sub_ext' for
> #<Rant::RacFileList:0x4026baf4>
> /usr/lib/ruby/gems/1.8/gems/rant-0.4.0/lib/rant/rantsys.rb:122:in
> `method_missing'
>
> /home/joe/repos/joe/learning/c_cpp_exercises/c++/problem_1_1/Rantfile:13:in
> `instance_eval'
>
> /usr/lib/ruby/gems/1.8/gems/rant-0.4.0/lib/rant/rantlib.rb:1002:in
> `instance_eval'
>
> /usr/lib/ruby/gems/1.8/gems/rant-0.4.0/lib/rant/rantlib.rb:1002:in
> `load_file'
>
> /usr/lib/ruby/gems/1.8/gems/rant-0.4.0/lib/rant/rantlib.rb:686:in `subdirs'
>
> And so on. Would that be fixed in the development version?

Yes.

--
Stefan