2011-11-27 56 views
1

我有一个帮助程序类,它扫描我的整个项目目录并收集源文件和相应(目标)对象文件的列表。扫描源目录后,定义了编译任务的依赖关系,如下所示。为Rake任务指定文件先决条件

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 

由于$proj是全球性的,DirectoryParser.new()的任何任务,被称为包括cleanclobber时被调用。这使得cleanclobber任务变慢,这是不可取的。

为了解决这个问题,我将所有生成的文件依赖项都移动到默认任务中。这使得我的cleanclobber任务更快,但是,我现在无法独立调用我的编译或链接任务。

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 

我该如何解决这个问题?我相信有人以前遇到过类似的问题。我会很感激任何帮助。

+0

我已决定保留上述相同的解决方案,花费的时间比我想要的要长一些。除非有人提出更好的解决方案? – thegreendroid

回答

0

我设法通过使用Singleton设计模式来优雅地解决这个问题,并完全避免使用Rake文件/任务依赖关系。 DirectoryParser现在是一个单独的类(在Ruby的内置“单身”库混合)

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 

现在我的清洁/撞任务是快,我仍然可以调用独立编译/链接任务。

3

你可以尝试两步法。

创建新任务generate_dependencies。 此任务用您的依赖关系和操作构建一个(静态)rake文件。

这个生成的rakefile可以加载到你的rake文件中。

一些示例代码(未经测试):

GENERATED = 'generated_dependencies.rb' 

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

    File.open(GENERATED, 'w') do |f| 
    $proj.source_files.each do |source_file| 
     f << <<-code 
     file #{source_file.obj_file} do 
     sh "gcc -c " #etc. 
     end 
     code 
    end 

    $proj.obj_files.each do |obj_file| 
     f << "task :compile => #{obj_file}" 
    end 

    #~ ... compile 
    #~ ... link 
    #~ ... execute 
    end 
end 

require GENERATED 

现在你有两个步骤:

  1. 创建一个空的“generated_dependencies.rb”(所以你得到任何错误,当你调用脚本第一次)
  2. 呼叫rake generate_dependencies
  3. 检查生成的文件 - 如果它不好,改变发电机;)
  4. 请致电rake compilerake link(或rake如果您要使用默认任务)... - 依赖关系在生成的文件中定义。

    • 当有些变化(新文件),从步骤2继续。
    • 如果结构保持不变(没有新的文件,只能更改代码),你只需要步骤4
+0

感谢您的回答。这是否意味着'rake generate_dependencies'和'rake install'必须由用户手动调用?这给使用者带来了不必要的负担,我并不是那么想。就用户而言,我希望透明地发生这种情况。 – thegreendroid

+0

我认为不是。我改变了一下我的答案。您可以根据需要定义默认值(例如序列编译,链接和执行)。在运行默认设置之前,您必须运行一次'rake generate_dependencies'。唯一的问题是:如果结构发生变化(新的源代码...),任何人都必须调用'rake generate_dependencies'来更新依赖关系。我试图得到一个“真正的”解决方案,但遇到了问题 - 同时我有了这个两步解决方案的想法。不是一个完整的解决方案,但有时最好有一半的解决方案,然后没有解决方案。 – knut

+0

再次感谢您的回复。手动运行'generate_dependencies'并不是我所追求的,因为它会给用户带来沉重的负担,记住一些可能非常容易出错的经验。我使用的解决方法是有效的,但唯一的缺点是你不能独立地调用编译/链接任务(你必须调用调用默认任务的'rake')。 – thegreendroid