-
Notifications
You must be signed in to change notification settings - Fork 627
Description
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
endFirst, 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.