How do I run a Rake task from a Rake task?

I have a Rakefile that compiles the project in two ways based on the global variable $build_type, which can be debug or: release (the result goes to a different directory):

task :build => [:some_other_tasks] do
end

I want to create a task that compiles the two configurations of the project in turn, as follows:

task :build_all do
  [ :debug, :release ].each do |t|
    $build_type = t
    # call task :build with all the tasks it depends on (?)
  end
end

Is there a way to call a task a method?Or how can I achieve similar results?

#1st floor

If you need to use tasks as a method, what about using the actual method?

task :build => [:some_other_tasks] do
  build
end

task :build_all do
  [:debug, :release].each { |t| build t }
end

def build(type = :debug)
  # ...
end

If you prefer to stick to rake's idioms, write your possibilities based on past answers:

  • This always performs tasks, but it does not perform its dependencies:

    Rake::Task["build"].execute
  • This execution dependency, but it only executes tasks without being invoked:

    Rake::Task["build"].invoke
  • This first resets the already_invoked state of the task, then executes the task again, dependencies and all:

    Rake::Task["build"].reenable Rake::Task["build"].invoke

    (Note that dependencies that have been invoked will not be reexecuted)

#2nd floor

If you want each task to run regardless of any failure, you can do the following:

task :build_all do
  [:debug, :release].each do |t| 
    ts = 0
    begin  
      Rake::Task["build"].invoke(t)
    rescue
      ts = 1
      next
    ensure
      Rake::Task["build"].reenable # If you need to reenable
    end
    return ts # Return exit code 1 if any failed, 0 if all success
  end
end

#3rd floor

I recommend not creating generic debugging and publishing tasks if the project is really compiled and results in files.You should use a file task that is very workable in your example, and as you mentioned, your output will go to a different directory.Assuming your project only compiles test.c files as out/debug/test.out and out/release/test.out using gcc, you can set up your project like this:

WAYS = ['debug', 'release']
FLAGS = {}
FLAGS['debug'] = '-g'
FLAGS['release'] = '-O'
def out_dir(way)
  File.join('out', way)
end
def out_file(way)
  File.join(out_dir(way), 'test.out')
end
WAYS.each do |way|
  desc "create output directory for #{way}"
  directory out_dir(way)

  desc "build in the #{way}-way"
  file out_file(way) => [out_dir(way), 'test.c'] do |t|
    sh "gcc #{FLAGS[way]} -c test.c -o #{t.name}"
  end
end
desc 'build all ways'
task :all => WAYS.map{|way|out_file(way)}

task :default => [:all]

This setting can be used as follows:

rake all # (builds debug and release)
rake debug # (builds only debug)
rake release # (builds only release)

This requires more, but it shows my point of view:

  1. Create output directory if necessary.
  2. Recompile the file only if necessary (this example only applies to the simplest test.c file).
  3. If you want to trigger a release or debug version, you can have all the tasks at any time.
  4. This example contains a way to define small differences between debug and release versions.
  5. There is no need to re-enable construction tasks that use global variables for parameterization, since different builds now have different tasks.Code reuse for build tasks is accomplished by reusing code to define build tasks.See how the loop does not perform the same task twice, but instead creates a task that can be triggered later (either by all tasks or by selecting one on the rake command line).

#4th floor

task :invoke_another_task do
  # some code
  Rake::Task["another:task"].invoke
end

#5th floor

task :build_all do
  [ :debug, :release ].each do |t|
    $build_type = t
    Rake::Task["build"].execute
  end
end

Posted by Tuck on Sat, 08 Feb 2020 18:26:19 -0800