# Incremental rebuild with Rake

**URL:** <https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184>\
**Category:** Ruby\
**Created:** [March 17, 2006, 6:48pm UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184 "2006-03-17T18:48:31Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 17, 2006, 6:48pm UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/1 "2006-03-17T18:48:31Z")

</div>

I am using Rake for testing c++ code.

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

–  
Simon S.

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

---

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 17, 2006, 6:56pm UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/2 "2006-03-17T18:56:26Z")

</div>

On 3/17/06, Simon S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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.

---

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 17, 2006, 8:55pm UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/3 "2006-03-17T20:55:56Z")

</div>

On 3/17/06, Simon S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> depends on the .h files.  
> Anything smarter than converting makedepend to ruby, like this?

–  
Simon S.

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’

---

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 17, 2006, 10:21pm UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/4 "2006-03-17T22:21:04Z")

</div>

Simon S. wrote:

> On 3/17/06, Simon S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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 W.

---

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 18, 2006, 1:35pm UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/5 "2006-03-18T13:35:29Z")

</div>

Simon S. wrote:

> On 3/17/06, Jim W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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 W.

---

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 18, 2006, 2:38pm UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/6 "2006-03-18T14:38:13Z")

</div>

On 3/18/06, Jim W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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

---

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 18, 2006, 12:21pm UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/7 "2006-03-18T12:21:52Z")

</div>

On 3/17/06, Jim W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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

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

---

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 19, 2006, 1:35am UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/8 "2006-03-19T01:35:29Z")

</div>

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

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;  
}

---

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 19, 2006, 1:41am UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/9 "2006-03-19T01:41:45Z")

</div>

On 3/19/06, Simon S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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/browse\_thread/thread/757aa464a524e8df/66e7b93cd8464833#msg\_b1345e404c2d7104](http://groups.google.com/group/comp.sys.mac.system/browse_thread/thread/757aa464a524e8df/66e7b93cd8464833#msg_b1345e404c2d7104)

---

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 19, 2006, 1:49am UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/10 "2006-03-19T01:49:34Z")

</div>

Simon S. 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 W.

---

<div class="post-metadata">

**Author:** ![simonsaid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b5e925/32.png) [@simonsaid](https://www.ruby-forum.com/u/simonsaid)\
**Post date:** [March 19, 2006, 2:17am UTC](https://www.ruby-forum.com/t/incremental-rebuild-with-rake/55184/11 "2006-03-19T02:17:57Z")

</div>

On 3/19/06, Jim W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Simon S. 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
