【问题标题】:Specifying file prerequisites for Rake task为 Rake 任务指定文件先决条件
【发布时间】:2011-11-27 07:39:53
【问题描述】:

我有一个帮助程序类,它扫描我的整个项目目录并收集源文件列表和相应的(目标)目标文件。编译任务的依赖是在扫描源码目录后定义的,如下图。

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 是全局的,当调用包括cleanclobber 在内的任何任务时都会调用DirectoryParser.new()。这使得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

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

【问题讨论】:

  • 我决定保留上面相同的解决方案,但代价是 cleanclobber 任务花费的时间比我想要的要长一些。除非有人提出更好的解决方案?

标签: ruby rake rake-task rakefile


【解决方案1】:

您可以尝试两步法。

创建一个新任务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 步。

【讨论】:

  • 感谢您的回答。这是否意味着用户必须手动调用“rake generate_dependencies”和“rake install”?这给用户带来了不必要的负担,我真的不想要这样。就用户而言,我希望这种情况透明地发生。
  • 我认为不是。我稍微改变了答案。您可以根据需要定义默认值(例如,序列编译、链接和执行)。在运行默认值之前,您必须运行一次rake generate_dependencies。您遇到的唯一问题:如果结构发生变化(新的源代码......),任何人都必须调用rake generate_dependencies 来更新依赖项。我试图得到一个“真正的”解决方案,但我遇到了问题——同时我有了这个两步解决方案的想法。不是真正的完整解决方案,但有时最好有一半的解决方案而不是没有解决方案。
  • 再次感谢您的回复。手动运行generate_dependencies 不是我所追求的,因为它会给用户带来负担,让用户记住事情和从经验中很容易出错。我使用的解决方法可行,但唯一的缺点是您不能独立调用编译/链接任务(您必须调用调用默认任务的rake)。
  • ...呃,我刚才还看到了其他几个。我建议您进行编辑以供您考虑。另外,为了确保文件存在,你可以touch GENERATED(方法存在,如果你不确定你总是可以sh "touch #{GENERATED}"
【解决方案2】:

通过使用 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

现在我的清理/破坏任务很快,我仍然可以独立调用编译/链接任务。

【讨论】:

    猜你喜欢
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多