From 80727d709c3a14c5f7b4ab14d7c59b8709dc133e Mon Sep 17 00:00:00 2001 From: Dmitry Goncharov Date: Sun, 2 Apr 2023 11:04:26 -0400 Subject: [SV 63856] Fix pruning of double-colon rules Given this setup: $ cat Makefile A::; @echo A-1 && sleep 1 && echo A-1 done A::; @echo A-2 && sleep 1 && echo A-2 done A::; @echo A-3 && sleep 1 && echo A-3 done B::; @echo B-1 && sleep 1 && echo B-1 done B::; @echo B-2 && sleep 1 && echo B-2 done B::; @echo B-3 && sleep 1 && echo B-3 done $ make -j8 A .WAIT B All recipes for A should be started sequentially and complete before any recipe for B is started, then all recipes for B should be started sequentially. This wasn't happening because the double-colon target was getting pruned too early. * src/remake.c (update_file): Don't prune a target if it's a double colon rule which is complete, but there are other recipes to run for this target: we want those other recipes to be run first. * tests/scripts/targets/WAIT: Test .WAIT with double colon rules. --- src/remake.c | 10 +- tests/scripts/targets/WAIT | 339 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 347 insertions(+), 2 deletions(-) diff --git a/src/remake.c b/src/remake.c index dec4667c..bdf78b3e 100644 --- a/src/remake.c +++ b/src/remake.c @@ -373,9 +373,15 @@ update_file (struct file *file, unsigned int depth) { /* Check for the case where a target has been tried and failed but the diagnostics haven't been issued. If we need the diagnostics - then we will have to continue. */ + then we will have to continue. + In the case of double colon rules, this file cannot be pruned if + this recipe finished (file->command_state == cs_finished) and there + are more double colon rules for this file. Instead the recipe of the + next double colon rule of this file should be run. */ if (!(f->updated && f->update_status > us_none - && !f->dontcare && f->no_diag)) + && !f->dontcare && f->no_diag) + && !(file->double_colon && file->command_state == cs_finished && + f->prev)) { DBF (DB_VERBOSE, _("Pruning file '%s'.\n")); return f->command_state == cs_finished ? f->update_status : us_success; diff --git a/tests/scripts/targets/WAIT b/tests/scripts/targets/WAIT index 343b87ac..4d56f6e7 100644 --- a/tests/scripts/targets/WAIT +++ b/tests/scripts/targets/WAIT @@ -298,5 +298,344 @@ all:;@: !, '', "#MAKEFILE#:2: .WAIT should not have prerequisites\n#MAKEFILE#:3: .WAIT should not have commands\n"); +# Wait for all double colon targets on the left, before building targets on the +# right. +# Subtest 1. First run this test without .WAIT and observe and A recipes +# interleave with B recipes. +# Then run the same test with .WAIT and observe that all A recipes get started +# sequentially before the 1st B recipe gets started and then all B recipes get +# started sequentially. + +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +run_make_test(q! +all: A B +A::; @#HELPER# -q out A-1 file A-1-done wait B-1-done out A-1-done +A::; @#HELPER# -q out A-2 file A-2-done wait B-2-done out A-2-done +A::; @#HELPER# -q out A-3 file A-3-done wait B-3-done out A-3-done +B::; @#HELPER# -q wait A-1-done out B-1 out B-1-done file B-1-done +B::; @#HELPER# -q wait A-2-done out B-2 out B-2-done file B-2-done +B::; @#HELPER# -q wait A-3-done out B-3 out B-3-done file B-3-done + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10', "A-1\nB-1\nB-1-done\nA-1-done\nA-2\nB-2\nB-2-done\nA-2-done\nA-3\nB-3\nB-3-done\nA-3-done\n"); + +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +# Subtest 2. +# Wait for all double colon targets on the left, before building targets on the +# right. + +run_make_test(q! +all: A .WAIT B +A::; @#HELPER# -q out $@-1 out $@-1-done +A::; @#HELPER# -q out $@-2 out $@-2-done +A::; @#HELPER# -q out $@-3 out $@-3-done +B::; @#HELPER# -q out $@-1 out $@-1-done +B::; @#HELPER# -q out $@-2 out $@-2-done +B::; @#HELPER# -q out $@-3 out $@-3-done + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10', "A-1\nA-1-done\nA-2\nA-2-done\nA-3\nA-3-done\nB-1\nB-1-done\nB-2\nB-2-done\nB-3\nB-3-done\n"); + +# sv 63856. +# Wait for all double colon targets on the left, before building targets on the +# right. +# Subtest 1. First run this test without .WAIT and observe and A recipes +# interleave with B recipes. +# Then run the same test with .WAIT and observe that all A recipes get started +# sequentially before the 1st B recipe gets started and then all B recipes get +# started sequentially. +# The targets are specified on the command line. + +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +run_make_test(q! +A::; @#HELPER# -q out A-1 file A-1-done wait B-1-done out A-1-done +A::; @#HELPER# -q out A-2 file A-2-done wait B-2-done out A-2-done +A::; @#HELPER# -q out A-3 file A-3-done wait B-3-done out A-3-done +B::; @#HELPER# -q wait A-1-done out B-1 out B-1-done file B-1-done +B::; @#HELPER# -q wait A-2-done out B-2 out B-2-done file B-2-done +B::; @#HELPER# -q wait A-3-done out B-3 out B-3-done file B-3-done + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10 A B', "A-1\nB-1\nB-1-done\nA-1-done\nA-2\nB-2\nB-2-done\nA-2-done\nA-3\nB-3\nB-3-done\nA-3-done\n"); + +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +# Subtest 2. +# sv 63856. +# Wait for all double colon targets on the left, before building targets on the +# right. The targets are specified on the command line. + +run_make_test(q! +A::; @#HELPER# -q out $@-1 out $@-1-done +A::; @#HELPER# -q out $@-2 out $@-2-done +A::; @#HELPER# -q out $@-3 out $@-3-done +B::; @#HELPER# -q out $@-1 out $@-1-done +B::; @#HELPER# -q out $@-2 out $@-2-done +B::; @#HELPER# -q out $@-3 out $@-3-done + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10 A .WAIT B', "A-1\nA-1-done\nA-2\nA-2-done\nA-3\nA-3-done\nB-1\nB-1-done\nB-2\nB-2-done\nB-3\nB-3-done\n"); + + +# Wait for all double colon targets on the left, before building targets on the +# right. +# Regular targets which have double colon targets as prerequisites. +# Subtest 1. First run this test without .WAIT and observe and A recipes +# interleave with B recipes. +# The targets are specified in the makefile. + +unlink('D', 'D-done', 'E', 'E-done'); +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +run_make_test(q! +all: C .WAIT A B +A::; @#HELPER# -q out A-1 file A-1-done wait B-1-done out A-1-done +A::; @#HELPER# -q out A-2 file A-2-done wait B-2-done out A-2-done +A::; @#HELPER# -q out A-3 file A-3-done wait B-3-done out A-3-done +B::; @#HELPER# -q wait A-1-done out B-1 out B-1-done file B-1-done +B::; @#HELPER# -q wait A-2-done out B-2 out B-2-done file B-2-done +B::; @#HELPER# -q wait A-3-done out B-3 out B-3-done file B-3-done + +C: D E +D:; @#HELPER# -q out D file D wait E-done out D-done +E:; @#HELPER# -q wait D out E out E-done file E-done + +.PHONY: C D E + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10', "D\nE\nE-done\nD-done\nA-1\nB-1\nB-1-done\nA-1-done\nA-2\nB-2\nB-2-done\nA-2-done\nA-3\nB-3\nB-3-done\nA-3-done\n"); + +# Wait for all double colon targets on the left, before building targets on the +# right. +# Regular targets which have double colon targets as prerequisites. +# Subtest 2. +# Run the same test with .WAIT and observe that all A recipes get started +# sequentially before the 1st B recipe gets started and then all B recipes get +# started sequentially. +# The targets are specified in the makefile. +# + +unlink('D', 'D-done', 'E', 'E-done'); +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +run_make_test(q! +all: C .WAIT A .WAIT B +A::; @#HELPER# -q out $@-1 out $@-1-done +A::; @#HELPER# -q out $@-2 out $@-2-done +A::; @#HELPER# -q out $@-3 out $@-3-done +B::; @#HELPER# -q out $@-1 out $@-1-done +B::; @#HELPER# -q out $@-2 out $@-2-done +B::; @#HELPER# -q out $@-3 out $@-3-done + +C: D E +D:; @#HELPER# -q out D file D wait E-done out D-done +E:; @#HELPER# -q wait D out E out E-done file E-done + +.PHONY: C D E + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10', "D\nE\nE-done\nD-done\nA-1\nA-1-done\nA-2\nA-2-done\nA-3\nA-3-done\nB-1\nB-1-done\nB-2\nB-2-done\nB-3\nB-3-done\n"); + + +# Wait for all double colon targets on the left, before building targets on the +# right. +# Regular targets which have double colon targets as prerequisites. +# Subtest 1. First run this test without .WAIT and observe and A recipes +# interleave with B recipes. +# The targets are specified on the command line. + +unlink('D', 'D-done', 'E', 'E-done'); +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +run_make_test(q! +A::; @#HELPER# -q out A-1 file A-1-done wait B-1-done out A-1-done +A::; @#HELPER# -q out A-2 file A-2-done wait B-2-done out A-2-done +A::; @#HELPER# -q out A-3 file A-3-done wait B-3-done out A-3-done +B::; @#HELPER# -q wait A-1-done out B-1 out B-1-done file B-1-done +B::; @#HELPER# -q wait A-2-done out B-2 out B-2-done file B-2-done +B::; @#HELPER# -q wait A-3-done out B-3 out B-3-done file B-3-done + +C: D E +D:; @#HELPER# -q out D file D wait E-done out D-done +E:; @#HELPER# -q wait D out E out E-done file E-done + +.PHONY: C D E + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10 C .WAIT A B', "D\nE\nE-done\nD-done\nA-1\nB-1\nB-1-done\nA-1-done\nA-2\nB-2\nB-2-done\nA-2-done\nA-3\nB-3\nB-3-done\nA-3-done\n"); + +# Wait for all double colon targets on the left, before building targets on the +# right. +# Regular targets which have double colon targets as prerequisites. +# Subtest 2. +# Run the same test with .WAIT and observe that all A recipes get started +# sequentially before the 1st B recipe gets started and then all B recipes get +# started sequentially. +# The targets are specified on the command line. + +unlink('D', 'D-done', 'E', 'E-done'); +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +run_make_test(q! +A::; @#HELPER# -q out $@-1 out $@-1-done +A::; @#HELPER# -q out $@-2 out $@-2-done +A::; @#HELPER# -q out $@-3 out $@-3-done +B::; @#HELPER# -q out $@-1 out $@-1-done +B::; @#HELPER# -q out $@-2 out $@-2-done +B::; @#HELPER# -q out $@-3 out $@-3-done + +C: D E +D:; @#HELPER# -q out D file D wait E-done out D-done +E:; @#HELPER# -q wait D out E out E-done file E-done + +.PHONY: C D E + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10 C .WAIT A .WAIT B', "D\nE\nE-done\nD-done\nA-1\nA-1-done\nA-2\nA-2-done\nA-3\nA-3-done\nB-1\nB-1-done\nB-2\nB-2-done\nB-3\nB-3-done\n"); + +unlink('D', 'D-done', 'E', 'E-done'); +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +# Wait for all double colon targets on the left, before building targets on the +# right. +# Double colon targets have reqular targets as prerequisites. +# Subtest 1. First run this test without .WAIT and observe and A recipes +# interleave with B recipes. +# The targets are specified in the makefile. + +unlink('D', 'D-done', 'E', 'E-done'); +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +run_make_test(q! +all: A B +A:: D; @#HELPER# -q out A-1 file A-1-done wait B-1-done out A-1-done +A::; @#HELPER# -q out A-2 file A-2-done wait B-2-done out A-2-done +A::; @#HELPER# -q out A-3 file A-3-done wait B-3-done out A-3-done +B:: E; @#HELPER# -q wait A-1-done out B-1 out B-1-done file B-1-done +B::; @#HELPER# -q wait A-2-done out B-2 out B-2-done file B-2-done +B::; @#HELPER# -q wait A-3-done out B-3 out B-3-done file B-3-done + +D:; @#HELPER# -q out D file D wait E-done out D-done +E:; @#HELPER# -q wait D out E out E-done file E-done + +.PHONY: D E + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10', "D\nE\nE-done\nD-done\nA-1\nB-1\nB-1-done\nA-1-done\nA-2\nB-2\nB-2-done\nA-2-done\nA-3\nB-3\nB-3-done\nA-3-done\n"); + +# Wait for all double colon targets on the left, before building targets on the +# right. +# Double colon targets have reqular targets as prerequisites. +# Subtest 2. +# Run the same test with .WAIT and observe that all A recipes get started +# sequentially before the 1st B recipe gets started and then all B recipes get +# started sequentially. +# The targets are specified in the makefile. + +unlink('D', 'D-done', 'E', 'E-done'); +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +run_make_test(q! +all: A .WAIT B +A:: D; @#HELPER# -q out $@-1 out $@-1-done +A:: ; @#HELPER# -q out $@-2 out $@-2-done +A:: ; @#HELPER# -q out $@-3 out $@-3-done +B:: E; @#HELPER# -q out $@-1 out $@-1-done +B:: ; @#HELPER# -q out $@-2 out $@-2-done +B:: ; @#HELPER# -q out $@-3 out $@-3-done + +D:; @#HELPER# -q out D out D-done +E:; @#HELPER# -q out E out E-done + +.PHONY: D E + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10', "D\nD-done\nA-1\nA-1-done\nA-2\nA-2-done\nA-3\nA-3-done\nE\nE-done\nB-1\nB-1-done\nB-2\nB-2-done\nB-3\nB-3-done\n"); + + +# Wait for all double colon targets on the left, before building targets on the +# right. +# Double colon targets have reqular targets as prerequisites. +# Subtest 1. First run this test without .WAIT and observe and A recipes +# interleave with B recipes. +# The targets are specified on the command line. + +unlink('D', 'D-done', 'E', 'E-done'); +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +run_make_test(q! +A:: D; @#HELPER# -q out A-1 file A-1-done wait B-1-done out A-1-done +A::; @#HELPER# -q out A-2 file A-2-done wait B-2-done out A-2-done +A::; @#HELPER# -q out A-3 file A-3-done wait B-3-done out A-3-done +B:: E; @#HELPER# -q wait A-1-done out B-1 out B-1-done file B-1-done +B::; @#HELPER# -q wait A-2-done out B-2 out B-2-done file B-2-done +B::; @#HELPER# -q wait A-3-done out B-3 out B-3-done file B-3-done + +D:; @#HELPER# -q out D file D wait E-done out D-done +E:; @#HELPER# -q wait D out E out E-done file E-done + +.PHONY: D E + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10 A B', "D\nE\nE-done\nD-done\nA-1\nB-1\nB-1-done\nA-1-done\nA-2\nB-2\nB-2-done\nA-2-done\nA-3\nB-3\nB-3-done\nA-3-done\n"); + +# Wait for all double colon targets on the left, before building targets on the +# right. +# Double colon targets have reqular targets as prerequisites. +# Subtest 2. +# Run the same test with .WAIT and observe that all A recipes get started +# sequentially before the 1st B recipe gets started and then all B recipes get +# started sequentially. +# The targets are specified on the command line. + +unlink('D', 'D-done', 'E', 'E-done'); +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + +run_make_test(q! +A:: D; @#HELPER# -q out $@-1 out $@-1-done +A:: ; @#HELPER# -q out $@-2 out $@-2-done +A:: ; @#HELPER# -q out $@-3 out $@-3-done +B:: E; @#HELPER# -q out $@-1 out $@-1-done +B:: ; @#HELPER# -q out $@-2 out $@-2-done +B:: ; @#HELPER# -q out $@-3 out $@-3-done + +D:; @#HELPER# -q out D out D-done +E:; @#HELPER# -q out E out E-done + +.PHONY: D E + +# This is just here so we don't fail with older versions of make +.WAIT: +!, + '-j10 A .WAIT B', "D\nD-done\nA-1\nA-1-done\nA-2\nA-2-done\nA-3\nA-3-done\nE\nE-done\nB-1\nB-1-done\nB-2\nB-2-done\nB-3\nB-3-done\n"); + +unlink('D', 'D-done', 'E', 'E-done'); +unlink('A-1-done', 'A-2-done', 'A-3-done', 'B-1-done', 'B-2-done', 'B-3-done'); + # This tells the test driver that the perl test script executed properly. 1; -- cgit v1.2.1