Search code examples
rubyrakerake-taskrakefile

Specifying file prerequisites for Rake task


I've got a helper class that scans my entire project directory and collects a list of source files and the corresponding (target) object files. The dependencies on the compile task is defined after scanning the source directory as shown below.

CLEAN.include(FileList[obj_dir + '**/*.o'])
CLOBBER.include(FileList[exe_dir + '**/*.exe'])

$proj = DirectoryParser.new(src_dir)

$proj.source_files.each do |source_file|
  file source_file.obj_file do
    sh "gcc -c ..."
  end
end

$proj.obj_files.each do |obj_file|
  task :compile => obj_file
end

task :compile do
end

Since $proj is global, the DirectoryParser.new() is invoked when any of the tasks are called including clean and clobber. This makes the clean and clobber tasks slow and that is not desirable.

To get around the problem I moved all the generation of File dependencies into the default task. This makes my clean and clobber tasks fast, however, I can't call my compile or link tasks independently now.

CLEAN.include(FileList[obj_dir + '**/*.o'])
CLOBBER.include(FileList[exe_dir + '**/*.exe'])

task :compile => $proj.source_files do   # Throws error!
end

task :default => do
  $proj = DirectoryParser.new(src_dir)

  $proj.source_files.each do |source_file|
    file source_file.obj_file do
      sh "gcc -c ..."
    end
  end

  $proj.obj_files.each do |obj_file|
    task :compile => obj_file
  end

  ... compile
  ... link
  ... execute
end

How do I get around this problem? I am sure someone has previously encountered a similar problem. I'd appreciate any help.


Solution

  • I managed to get around this problem elegantly by using the Singleton design pattern and moving away from using Rake file/task dependencies completely. DirectoryParser is now a singleton class (by mixing in Ruby's built-in 'singleton' library)

    CLEAN.include(FileList[obj_dir + '**/*.o'])
    CLOBBER.include(FileList[exe_dir + '**/*.exe'])
    
    task :compile do
      $proj = DirectoryParser.instance
      $proj.source_files.each do |source_file|
          sh "gcc -c ..." unless uptodate?(obj_file, source_file)
      end
    end
    
    task :link do
      $proj = DirectoryParser.instance
      ...
    end
    

    Now my clean/clobber tasks are fast and I can still call compile/link tasks independently.