From: Brad Phelan Date: 2007-08-16T18:59:58+09:00 Subject: Re: Rake and Rant Brad Phelan wrote: > Jim Weirich wrote: >> Brad Phelan wrote: >>> Still a native Ruby solution would be nicer. >> >> If someone wanted to contribute a dependency scanner for their >> favorite language to the Rake project, I would be willing to consider >> it for inclusion. >> >> A C/C++ scanner shouldn't be that hard to write. Its just that I've >> not working in a C/C++ project since starting Rake, so I've never had >> the need to write one. >> >> -- >> -- Jim Weirich > > > With regards to the RANT project http://rubyforge.org/projects/make/ > where I nicked the scanner this should do the job. > > =========================================== > > module Rake > module C > module Include > def Include.depends(file) > File.open file do |f| > txt = f.read > parse_includes txt > end > end > > # Searches for all `#include' statements in the C/C++ source > # from the string +src+. > # > # Returns two arguments: > # 1. A list of all standard library includes (e.g. #include > ). > # 2. A list of all local includes (e.g. #include "stdio.h"). > def Include.parse_includes(src) > if src.respond_to? :to_str > src = src.to_str > else > raise ArgumentError, "src has to be a string" > end > s_includes = [] > l_includes = [] > in_block_comment = false > prev_line = nil > src.each { |line| > line.chomp! > if block_start_i = line.index("/*") > c_start_i = line.index("//") > if !c_start_i || block_start_i < c_start_i > if block_end_i = line.index("*/") > if block_end_i > block_start_i > line[block_start_i..block_end_i+1] = "" > end > end > end > end > if prev_line > line = prev_line << line > prev_line = nil > end > if line =~ /\\$/ > prev_line = line.chomp[0...line.length-1] > end > if in_block_comment > in_block_comment = false if line =~ %r|\*/| > next > end > case line > when /\s*#\s*include\s+"([^"]+)"/ > l_includes << $1 > when /\s*#\s*include\s+<([^>]+)>/ > s_includes << $1 > when %r|(?!//)[^/]*/\*| > in_block_comment = true > end > } > [s_includes, l_includes] > end > end > end > end > > > # RAKE Rule figures out the dependencies for the C file > > rule( /\.o$/ => > > proc do |task_name| > a = [] > name = task_name.sub(/\.[^.]+$/, '.c') > s_includes, l_includes = Rake::C::Include.depends(name) > a << name > a << l_includes > a > end > > ) do |t| > sh "cc #{t.source} -c -o #{t.name}" > end > > > The scanner is not recursive yet but should be simple > to implement but I have to run ...... > > Regards > > -- > Brad Phelan > http://xtargets.com > My simple test rake file was ++++++++++++++++++++++++++++++++++++++ require 'cscanner' task :default => 'main.out' file 'main.out' => [ 'main.o' ] do |t| sh "cc -o #{t.name} #{t.prerequisites.join(' ')}" end +++ and the C/H file was +++ #include #include #include "main.h" int main ( int argc, char * argv[] ){ printf("Hello world"); return 0; } ++ #ifndef _MAIN_ #define _MAIN_ typedef struct { int a; int b; } Foo; #endif and it seemed to work ok