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 
> <stdio.h>).
>          # 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 <stdio.h>
#include <stdlib.h>
#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