Skip to content

multitasks continue their execution even if prerequisite fails #190

@mbunkus

Description

@mbunkus

Problem summary: With the following Rakefile rake v12.0.0 continues building the "apps" even though one of its prerequisites (the "sources") fails.

This Rakefile is a dumbed-down version of my application's build system. There are several applications that all depend on a common library. This library in turn depends on several object files, and for each object file there's a single source file. There's a rule that compiles those source files into object files.

It's the basic C++ application model: several .cpp get turned into .o, those .o are linked into a .a, several applications link against that .a.

What happens, though, is that even if turning one of those .cpp into an .o fails (and therefore the .a cannot be built) the linker for the applications is still invoked. That linking step fails, as the library isn't found.

Here's the synthetic Rakefile that reproduces this issue:

num_sources   = 20
num_apps      = 8

apps          = (1..num_apps).map { |i| "app#{i}" }
objects       = (1..num_sources).map { |i| "source#{i}.o" }
sources       = (1..num_sources).map { |i| "source#{i}.cpp" }

$stdout_mutex = Mutex.new

def log text
  $stdout_mutex.synchronize {
    puts "#{Time.now} #{text}"
  }
end

task :default => apps

task :clean do
  (apps + objects + ["library"]).each do |name|
    File.unlink(name) if FileTest.exists?(name)
  end

  system "touch #{sources.join(' ')}"
end

compiler = lambda do |*args|
  log "Compiling #{args.first.name}"
  system "sleep 2"

  if args.first.name == "source4.o"
    log "Will throw an exception for source4.o"
    fail
  end
end

rule '.o' => '.cpp', &compiler

file "library" => objects do
  log "Creating library"
  system "touch library"
end

(1..num_apps).each do |i|
  file "app#{i}" => "library" do
    log "Creating app#{i}"
    system "touch app#{i}"
  end
end

First, run rake clean. This will create the dummy source files source1.cpp through source20.cpp. Next, run rake -m. You'll observe the following output:

2017-01-21 12:56:07 +0100 Compiling source1.o
2017-01-21 12:56:09 +0100 Compiling source2.o
2017-01-21 12:56:11 +0100 Compiling source3.o
2017-01-21 12:56:13 +0100 Compiling source4.o
2017-01-21 12:56:15 +0100 Will throw an exception for source4.o
2017-01-21 12:56:15 +0100 Creating app2
rake aborted!

/home/mosu/tmp/Rakefile:34:in `block in <top (required)>'
Tasks: TOP => default => app1 => library => source4.o
2017-01-21 12:56:15 +0100 Creating app4
(See full trace by running task with --trace)
2017-01-21 12:56:15 +0100 Creating app5

You can see that Rake aborts building app1, but it it still tries to create app4 and app5. Neither of those should have been continued as their prerequisite library has failed. Which of those other appX targets is continued depends on timing; it's not always 4 and 5.

Just for fun I've tried the same Rakefile with drake -j8 instead of rake -m. drake handles this case correctly and doesn't continue building any of the other appX targets.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions