【问题标题】:Difference between order_only prerequisites and non-order_only prerequisites in rakerake 中 order_only 先决条件和 non-order_only 先决条件之间的区别
【发布时间】:2021-12-30 06:14:31
【问题描述】:

Rake 在13.0 中添加了一个order_only 功能,它可能基于GNU Make 的order-only prerequisites

question 进一步阐明了有关仅限订单的先决条件应如何工作的信息。

但问题是我看不到它在 rake 中的实际工作方式。例如,如果我运行rake install,然后运行rake build,当build 不是它的唯一先决条件时,rake install 不会再次运行。也许我只是被误导了,或者可能是其他一些因素,例如时间戳以及 needed? 方法如何影响它的行为,但是我有点厌倦了进一步检查 rake 的源代码。

在合并提交中,仅顺序的先决条件似乎与prerequisites 的分配方式不同,没有其他任何内容。

无论如何,我希望有人能详细描述order_only 应该如何完整地在 rake 中工作;如果可能,显示示例并引用 rake 的源代码。这将极大地帮助我和其他 Rakefile 编写者。

【问题讨论】:

    标签: ruby rake


    【解决方案1】:

    在我看来,有人添加了这个,以便您可以在 Rake 中构建一些 order_only 命令,但没有将对此的支持添加到内置文件命令中。它确实将 order_only 先决条件存储在任务中的单独成员变量中,因此您可以制作自己的 FileTask 版本,该版本将像 GNU Make 的仅订单先决条件一样工作。这是一个示例 Rakefile:

    class OrderOnlyFileTask < Rake::FileTask
      def out_of_date?(stamp)
        all_regular_prerequisite_tasks.any? { |prereq|
          prereq_task = application[prereq, @scope]
          if prereq_task.instance_of?(Rake::FileTask)
            prereq_task.timestamp > stamp || @application.options.build_all
          else
            prereq_task.timestamp > stamp
          end
        }
      end
      
      def all_regular_prerequisite_tasks
        seen = {}
        collect_regular_prerequisites(seen)
        seen.values
      end
      
      def collect_regular_prerequisites(seen)
        regular_prerequisite_tasks.each do |pre|
          next if seen[pre.name]
          seen[pre.name] = pre
          pre.collect_prerequisites(seen)
        end
      end
      
      def regular_prerequisite_tasks
        prerequisites.map { |pre| lookup_prerequisite(pre) }
      end
    end   
    
    file 'foo/created.txt' do
      mkdir 'foo'
      touch 'foo/created.txt'
    end
    
    file 'source.txt' do
      touch 'source.txt'
    end
    
    OrderOnlyFileTask.define_task('foo/built.txt' => ['source.txt'], order_only: ['foo/created.txt']) do
      touch 'foo/built.txt'
    end
    
    task :build => 'foo/built.txt' do
      puts 'build'
    end
    

    如果我从头开始运行rake build,我会得到以下输出:

    % rake build
    touch source.txt
    mkdir foo
    touch foo/created.txt
    touch foo/built.txt
    build
    

    如果我再次运行它:

    % rake build
    build
    

    如果我更新 foo/created.txt 上的 mtime:

    % touch foo/created.txt
    % rake build
    build
    

    如果我修改源文件:

    % touch source.txt
    % rake build
    touch foo/built.txt
    build
    

    如果我删除 foo 目录:

    % rm -rf foo
    % rake build
    mkdir foo
    touch foo/created.txt
    touch foo/built.txt
    build
    

    如果您将 OrderOnlyFileTask 更改为 foo/created.txt 的常规先决条件,如下所示:

    OrderOnlyFileTask.define_task('foo/built.txt' => ['source.txt', 'foo/created.txt']) do
      touch 'foo/built.txt'
    end
    

    然后当 foo/created.txt 被触摸时你会得到不同的行为:

    % touch foo/created.txt
    % rake build
    touch foo/built.txt
    build
    

    我在这里将依赖项设为文件 (foo/created.txt) 而不是 GNU Make 示例中的目录,因为 Rake 中的目录任务不会像 make 中的目录依赖项那样检查目录的 mtime。

    因此,使用任务的 order_only 选项,您可以构建自己的 Rake 任务,在决定是否执行时以不同的方式处理 order_only 先决条件。你只需要在你的任务中定义needed? 来处理你想要的先决条件。我在 OrderOnlyFileTask 中放置的所有这些方法都是更改 FileTask 中的 needed? 方法以忽略 order_only 先决条件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多