Forum: Ruby incremental rebuild with Rake

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
896cfc242a7762467c2a0b2af86598e5?d=identicon&s=25 Simon Strandgaard (Guest)
on 2006-03-17 18:48
(Received via mailing list)
I am using Rake for testing c++ code.

Incremental rebuild does not work for .h files,
Any ideas?


--
Simon Strandgaard






require 'rake/clean'

APPLICATION = 'test_code.exe'

CC = 'g++'
LD = CC

CFLAGS = [
  '-pedantic',
  '-fprofile-arcs -ftest-coverage',
  `cppunit-config --cflags`.strip
].join(' ')

LIBS = [
  `cppunit-config --libs`.strip
].join(' ')


CPP_SOURCES = FileList['test_code/*.cpp'] + FileList['code/*.cpp']

O_FILES = CPP_SOURCES.sub(/\.cpp$/, '.o')

file APPLICATION => O_FILES do |t|
  sh "#{LD} #{LIBS} #{O_FILES} -o #{t.name}"
end

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


CLEAN.include("**/*.o")
CLEAN.include("**/*.bb")
CLEAN.include("**/*.bbg")
CLEAN.include("**/*.da")
CLOBBER.include(APPLICATION)
CLOBBER.include("**/*.gcov")


desc "compile the test executable."
task :compile => APPLICATION


desc "run all the tests."
task :test => APPLICATION do
  sh "./#{APPLICATION}"
end


rule ".gcov" => [".cpp"] do |t|
  path = t.source.sub(/\/[^\/]+\.cpp$/, '')
  sh "gcov -p --object-directory #{path} #{t.source}"
end


GCOV_FILES = CPP_SOURCES.sub(/\.cpp$/, '.gcov')

desc "output coverage info."
task :coverage => GCOV_FILES


task :default => :test
896cfc242a7762467c2a0b2af86598e5?d=identicon&s=25 Simon Strandgaard (Guest)
on 2006-03-17 18:56
(Received via mailing list)
On 3/17/06, Simon Strandgaard <neoneye@gmail.com> wrote:
> I am using Rake for testing c++ code.
>
> Incremental rebuild does not work for .h files,
> Any ideas?

I have made some changes to my .h files
and nothing happens when I type 'rake'!

I wonder how to describe, that the application also
depends on the .h files.
896cfc242a7762467c2a0b2af86598e5?d=identicon&s=25 Simon Strandgaard (Guest)
on 2006-03-17 20:55
(Received via mailing list)
On 3/17/06, Simon Strandgaard <neoneye@gmail.com> wrote:
> depends on the .h files.
Anything smarter than converting makedepend to ruby, like this?

--
Simon Strandgaard



task :depend do
  sh "makedepend -f- -- #{CFLAGS} -- #{CPP_SOURCES} > .depend"
end



=begin
input:
code.o: code.h morecode.h

output:
{'code.o' => ['code.h', 'morecode.h']}
=end
def convert_makedepend_to_hash(filename)
  lines1 = IO.readlines(filename)
  # get rid of comments and empty lines
  lines2 = lines1.reject{|line| line  =~ /^#|^\s*$/ }

  deps = {}
  lines2.each do |line|
    o_file, h_files_str = line.strip.split(': ')
    h_files = h_files_str.split(' ')
    deps[o_file] = h_files
  end

  deps
end


task :rakedepend do
  deps = convert_makedepend_to_hash('.depend')
  #p deps

  ary = []
  deps.each do |o_file, deps|
    s = 'file "' + o_file + '" => ' + deps.inspect
    ary << s
  end
  result = ary.join("\n")
  result += "\n\n"
  File.open('.rakedepends', 'w+') {|f| f.write(result)}
end

load '.rakedepends'
10d4acbfdaccb4eee687a428ca00a5d8?d=identicon&s=25 Jim Weirich (weirich)
on 2006-03-17 22:21
Simon Strandgaard wrote:
> On 3/17/06, Simon Strandgaard <neoneye@gmail.com> wrote:
>> depends on the .h files.
> Anything smarter than converting makedepend to ruby, like this?

Actually, its a bit easier than that ... but its a poorly documented
area of Rake.

Rake supports dependency files by importing them, like this:

   require 'rake/loaders/makefile'  # Load the makefile dependency
loader
   import '.depend.mf'              # Import the dependencies.

(notice the .mf extension, that tells Rake that the dependencies are in
makefile format).

So just create a task that builds the dependency files, similar to the
above.

   file '.depend.mf' do
     sh "makedepend -f- -- #{CFLAGS} -- #{CPP_SOURCES} > .depend.mf"
   end

After the Rakefile has been read, but before the user requested targets
are built, Rake will check to see if any imported dependencies have been
requested.  If they have, rake will run any build targets for the
dependencies (i.e. if the dependency file is out of date, it will
rebuild it).  It will then load the dependencies (no need to convert
makefile style dependencies, rake will parse the file if the makefile
loader has been required as shown above).

The only gotcha in the scenario is that the dependency file rebuild
cannot be triggered by any of the dependencies defined in the file
(since the that file has not been loaded yet).

--
-- Jim Weirich
896cfc242a7762467c2a0b2af86598e5?d=identicon&s=25 Simon Strandgaard (Guest)
on 2006-03-18 12:21
(Received via mailing list)
On 3/17/06, Jim Weirich <jim@weirichhouse.org> wrote:
[snip]
> Rake supports dependency files by importing them, like this:
[snip]


Touching 'a.cpp' does not result in a compile, what am I doing wrong?
(Touching 'a.h' works fine.)

prompt> ls
Rakefile        a.cpp           a.h             main.cpp
prompt> rake
(in /Users/simonstrandgaard/rake)
makedepend -f- --  -- a.cpp main.cpp > .depend.mf
makedepend: warning:  a.cpp (reading a.h, line 4): cannot find include
file "string"
        not in /usr/local/lib/gcc-include/string
        not in /usr/include/string
g++ -c -o a.o a.cpp
g++ -c -o main.o main.cpp
g++ a.o main.o -o test.exe
prompt> ./test.exe
test a
prompt> touch a.h
prompt> rake
(in /Users/simonstrandgaard/rake)
g++ -c -o a.o a.cpp
g++ -c -o main.o main.cpp
g++ a.o main.o -o test.exe
prompt> touch a.cpp
prompt> rake
(in /Users/simonstrandgaard/rake)
prompt>



Below are my files



prompt> cat .depend.mf
# DO NOT DELETE

a.o: a.h
main.o: a.h






prompt> cat a.h
#ifndef __A_H__
#define __A_H__

#include <string>

std::string test_a();

#endif // __A_H__






prompt> cat a.cpp
#include "a.h"

std::string test_a()
{
        return std::string("a");
}






prompt> cat main.cpp
#include "a.h"

int main(int argc, char **argv)
{
        std::string s = test_a();
        printf("test %s\n", s.c_str());
        return 0;
}






prompt> cat Rakefile
require 'rake/clean'
require 'rake/loaders/makefile'

APPLICATION = 'test.exe'
CPP_FILES = FileList['*.cpp']
O_FILES = CPP_FILES.sub(/\.cpp$/, '.o')

file '.depend.mf' do
    sh "makedepend -f- --  -- #{CPP_FILES} > .depend.mf"
end

import ".depend.mf"

file APPLICATION => O_FILES do |t|
  sh "g++ #{O_FILES} -o #{t.name}"
end

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

CLEAN.include("**/*.o")
CLEAN.include(APPLICATION)
CLEAN.include(".depend.mf")

task :default => APPLICATION
10d4acbfdaccb4eee687a428ca00a5d8?d=identicon&s=25 Jim Weirich (weirich)
on 2006-03-18 13:35
Simon Strandgaard wrote:
> On 3/17/06, Jim Weirich <jim@weirichhouse.org> wrote:
> [snip]
>> Rake supports dependency files by importing them, like this:
> [snip]
>
>
> Touching 'a.cpp' does not result in a compile, what am I doing wrong?
> (Touching 'a.h' works fine.)

Ahh, evidently, makedepend does not create an explicit dependency
between a.o and a.cpp.  Make probably deduces this implicitly.  however,
rake does not.  So just make the relationship explicit.  Add the
following to your Rakefile:

CPP_FILES.each do |src|
  file src.ext(".o") => src
end

--
-- Jim Weirich
896cfc242a7762467c2a0b2af86598e5?d=identicon&s=25 Simon Strandgaard (Guest)
on 2006-03-18 14:38
(Received via mailing list)
On 3/18/06, Jim Weirich <jim@weirichhouse.org> wrote:
> CPP_FILES.each do |src|
>   file src.ext(".o") => src
> end
>

Excellent.. Now incremental rebuild is working
for both .h files and .cpp files.

Thanks Jim.





Below are the final rakefile, maybe handy for others.



require 'rake/clean'
require 'rake/loaders/makefile'

APPLICATION = 'test.exe'
CPP_FILES = FileList['*.cpp']
O_FILES = CPP_FILES.sub(/\.cpp$/, '.o')

file '.depend.mf' do
  sh "makedepend -f- --  -- #{CPP_FILES} > .depend.mf"
end

import ".depend.mf"

file APPLICATION => O_FILES do |t|
  sh "g++ #{O_FILES} -o #{t.name}"
end

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

CPP_FILES.each do |src|
  file src.ext(".o") => src
end

CLEAN.include("**/*.o")
CLEAN.include(APPLICATION)
CLEAN.include(".depend.mf")

task :default => APPLICATION
896cfc242a7762467c2a0b2af86598e5?d=identicon&s=25 Simon Strandgaard (Guest)
on 2006-03-19 01:35
(Received via mailing list)
I have noticed that the '.exe' file sometimes is'nt being linked.
What could be the reason for this?


Does'nt matter if I touch .h files or .cpp files.
Pretty odd.  Any ideas?  (maybe osx issue?)



prompt> touch a.h
prompt> rake
(in /Users/simonstrandgaard/rake)
g++ -c -o a.o a.cpp
g++ -c -o main.o main.cpp
g++ a.o main.o -o test.exe
prompt> touch a.h
prompt> rake
(in /Users/simonstrandgaard/rake)
g++ -c -o a.o a.cpp
g++ -c -o main.o main.cpp
prompt>




prompt> touch a.cpp
prompt> rake
(in /Users/simonstrandgaard/rake)
g++ -c -o a.o a.cpp
g++ a.o main.o -o test.exe
prompt> touch a.cpp
prompt> rake
(in /Users/simonstrandgaard/rake)
g++ -c -o a.o a.cpp
prompt>




prompt> touch main.cpp
prompt> rake
(in /Users/simonstrandgaard/rake)
g++ -c -o main.o main.cpp
prompt> touch main.cpp
prompt> rake
(in /Users/simonstrandgaard/rake)
g++ -c -o main.o main.cpp
g++ a.o main.o -o test.exe
prompt>




prompt> uname -a
Darwin case.local 7.9.0 Darwin Kernel Version 7.9.0: Wed Mar 30
20:11:17 PST 2005; root:xnu/xnu-517.12.7.obj~1/RELEASE_PPC  Power
Macintosh powerpc
prompt> rake --version
rake, version 0.5.4
prompt> ruby -v
ruby 1.8.2 (2004-11-03) [powerpc-darwin7.5.0]
prompt>



prompt> rake -P
(in /Users/simonstrandgaard/rake)
rake .depend.mf
rake a.o
    a.cpp
    a.h
rake clean
rake clobber
    clean
rake default
    test.exe
rake main.o
    main.cpp
    a.h
rake test.exe
    a.o
    main.o
prompt>





prompt> cat .depend.mf
# DO NOT DELETE

a.o: a.h
main.o: a.h





prompt> cat Rakefile
require 'rake/clean'
require 'rake/loaders/makefile'

APPLICATION = 'test.exe'
CPP_FILES = FileList['*.cpp']
O_FILES = CPP_FILES.sub(/\.cpp$/, '.o')

file '.depend.mf' do
  sh "makedepend -f- --  -- #{CPP_FILES} > .depend.mf"
end

import ".depend.mf"

file APPLICATION => O_FILES do |t|
  sh "g++ #{O_FILES} -o #{t.name}"
end

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

CPP_FILES.each do |src|
  file src.ext(".o") => src
end

CLEAN.include("**/*.o")
CLEAN.include(APPLICATION)
CLEAN.include(".depend.mf")

task :default => APPLICATION






prompt> cat a.h
#ifndef __A_H__
#define __A_H__

#include <string>

std::string test_a();

#endif // __A_H__






prompt> cat a.cpp
#include "a.h"

std::string test_a()
{
        return std::string("a");
}






prompt> cat main.cpp
#include "a.h"

int main(int argc, char **argv)
{
        std::string s = test_a();
        printf("test %s\n", s.c_str());
        return 0;
}
896cfc242a7762467c2a0b2af86598e5?d=identicon&s=25 Simon Strandgaard (Guest)
on 2006-03-19 01:41
(Received via mailing list)
On 3/19/06, Simon Strandgaard <neoneye@gmail.com> wrote:
> I have noticed that the '.exe' file sometimes is'nt being linked.
> What could be the reason for this?
>
>
> Does'nt matter if I touch .h files or .cpp files.
> Pretty odd.  Any ideas?  (maybe osx issue?)


seems to be an osx issue with disk caching.

http://groups.google.com/group/comp.sys.mac.system...
10d4acbfdaccb4eee687a428ca00a5d8?d=identicon&s=25 Jim Weirich (weirich)
on 2006-03-19 01:49
Simon Strandgaard wrote:
> I have noticed that the '.exe' file sometimes is'nt being linked.
> What could be the reason for this?

I'm not able to reproduce this.  Hmmmm.

Check the time stamps on the .o and .exe files.  If the .exe is older
than the .o files, rake should attempt to rebuild it.

-- Jim Weirich
896cfc242a7762467c2a0b2af86598e5?d=identicon&s=25 Simon Strandgaard (Guest)
on 2006-03-19 02:17
(Received via mailing list)
On 3/19/06, Jim Weirich <jim@weirichhouse.org> wrote:
> Simon Strandgaard wrote:
> > I have noticed that the '.exe' file sometimes is'nt being linked.
> > What could be the reason for this?
>
> I'm not able to reproduce this.  Hmmmm.
>
> Check the time stamps on the .o and .exe files.  If the .exe is older
> than the .o files, rake should attempt to rebuild it.


After reading on the mac groups.. the solution seems to be
doing "ls #{t.name} > /dev/null" after each operation.
I would prefer a cleaner solution to this!


Anyways thanks for the help (and for rake).



file APPLICATION => O_FILES do |t|
  sh "g++ #{O_FILES} -o #{t.name}"
  system("ls #{t.name} > /dev/null")
end

rule ".o" => [".cpp"] do |t|
  sh "g++ -c -o #{t.name} #{t.source}"
  system("ls #{t.name} > /dev/null")
end
This topic is locked and can not be replied to.