aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2022-11-03 15:49:11 +0000
committerRon Yorston <rmy@pobox.com>2022-11-03 15:52:48 +0000
commit5f64589b84a7349316a04cdbe607a5824459b731 (patch)
treedae9145ccae5e67012ab172789f9bcb099db40dd
parent0aceca8673c1d9a8bc34faa460389768efa08eb7 (diff)
downloadbusybox-w32-5f64589b84a7349316a04cdbe607a5824459b731.tar.gz
busybox-w32-5f64589b84a7349316a04cdbe607a5824459b731.tar.bz2
busybox-w32-5f64589b84a7349316a04cdbe607a5824459b731.zip
make: fixes to inference rules
Austin Group defect report 875 clarifies some aspects of inference rules. The crux of the issue is related to chained inference rules so it doesn't affect POSIX mode. The test makefile looks like this: .SUFFIXES: .a .b .c .a.c: @echo .a.c .b.c: @echo .b.c test.c: test.b test.a: test.b: The correct output is deemed to be '.a.c'. Additional complications are: - whether or not the prerequisite files are present; - the use of the suffixes '.a' and '.c' may result in the builtin inference rule '.c.a' being considered. In favourable circumstances pdpmake managed to give the correct result, in unfavourable it reported circular dependencies or segfaulted. Changes to fix these issues are: - When prerequisites are being recursively built the standard says: 'Upon recursion, each prerequisite shall become a target itself.' Follow this requirement. - At the end of make() the target being built should have its time (as represented by n_tim in struct name) updated when any action has been taken. - When dyndep() is looking for prerequisites it should: * skip candidates that are in the process of being built; * consider whether an explicit candidate is a target, not whether it has any commands associated with it. pdpmake now behaves similarly to GNU make when presented with makefiles like the above. bmake gives the incorrect output '.b.c'.
-rw-r--r--miscutils/make.c39
-rwxr-xr-xtestsuite/make.tests39
2 files changed, 60 insertions, 18 deletions
diff --git a/miscutils/make.c b/miscutils/make.c
index daad75f5c..86d06e970 100644
--- a/miscutils/make.c
+++ b/miscutils/make.c
@@ -717,21 +717,23 @@ dyndep(struct name *np, struct rule *imprule)
717 sp = findname(auto_concat(newsuff, suff)); 717 sp = findname(auto_concat(newsuff, suff));
718 if (sp && sp->n_rule) { 718 if (sp && sp->n_rule) {
719 // Generate a name for an implicit prerequisite 719 // Generate a name for an implicit prerequisite
720 pp = newname(auto_concat(base, newsuff)); 720 struct name *ip = newname(auto_concat(base, newsuff));
721 if (!pp->n_tim.tv_sec) 721 if ((ip->n_flag & N_DOING))
722 modtime(pp); 722 continue;
723 if ((!chain && (pp->n_tim.tv_sec || getcmd(pp))) || 723 if (!ip->n_tim.tv_sec)
724 (chain && dyndep(pp, NULL))) { 724 modtime(ip);
725 if (chain ? ip->n_tim.tv_sec || (ip->n_flag & N_TARGET) :
726 dyndep(ip, NULL) != NULL) {
725 // Prerequisite exists or we know how to make it 727 // Prerequisite exists or we know how to make it
726 if (imprule) { 728 if (imprule) {
727 dp = NULL; 729 dp = NULL;
728 newdep(&dp, pp); 730 newdep(&dp, ip);
729 imprule->r_dep = dp; 731 imprule->r_dep = dp;
730 imprule->r_cmd = sp->n_rule->r_cmd; 732 imprule->r_cmd = sp->n_rule->r_cmd;
731 } 733 }
734 pp = ip;
732 goto finish; 735 goto finish;
733 } 736 }
734 pp = NULL;
735 } 737 }
736 } 738 }
737 } 739 }
@@ -2121,6 +2123,7 @@ make(struct name *np, int level)
2121 } 2123 }
2122 for (dp = rp->r_dep; dp; dp = dp->d_next) { 2124 for (dp = rp->r_dep; dp; dp = dp->d_next) {
2123 // Make prerequisite 2125 // Make prerequisite
2126 dp->d_name->n_flag |= N_TARGET;
2124 estat |= make(dp->d_name, level + 1); 2127 estat |= make(dp->d_name, level + 1);
2125 2128
2126 // Make strings of out-of-date prerequisites (for $?), 2129 // Make strings of out-of-date prerequisites (for $?),
@@ -2166,28 +2169,28 @@ make(struct name *np, int level)
2166 2169
2167 if (quest) { 2170 if (quest) {
2168 if (timespec_le(&np->n_tim, &dtim)) { 2171 if (timespec_le(&np->n_tim, &dtim)) {
2169 clock_gettime(CLOCK_REALTIME, &np->n_tim); 2172 didsomething = 1;
2170 return 1; // 1 means rebuild is needed 2173 estat = 1; // 1 means rebuild is needed
2171 } 2174 }
2172 } else if (!(np->n_flag & N_DOUBLE) && 2175 } else if (!(np->n_flag & N_DOUBLE) &&
2173 ((np->n_flag & N_PHONY) || (timespec_le(&np->n_tim, &dtim)))) { 2176 ((np->n_flag & N_PHONY) || (timespec_le(&np->n_tim, &dtim)))) {
2174 if (estat == 0) { 2177 if (estat == 0) {
2175 if (!sc_cmd) { 2178 if (sc_cmd)
2176 if (!doinclude)
2177 bb_error_msg("nothing to be done for %s", np->n_name);
2178 } else {
2179 estat = make1(np, sc_cmd, oodate, allsrc, dedup, impdep); 2179 estat = make1(np, sc_cmd, oodate, allsrc, dedup, impdep);
2180 clock_gettime(CLOCK_REALTIME, &np->n_tim); 2180 else if (!doinclude)
2181 } 2181 bb_error_msg("nothing to be done for %s", np->n_name);
2182 didsomething = 1;
2182 } else if (!doinclude) { 2183 } else if (!doinclude) {
2183 bb_error_msg("'%s' not built due to errors", np->n_name); 2184 bb_error_msg("'%s' not built due to errors", np->n_name);
2184 } 2185 }
2185 free(oodate); 2186 free(oodate);
2186 } else if (didsomething) { 2187 }
2188
2189 if (didsomething)
2187 clock_gettime(CLOCK_REALTIME, &np->n_tim); 2190 clock_gettime(CLOCK_REALTIME, &np->n_tim);
2188 } else if (level == 0) { 2191 else if (!quest && level == 0)
2189 printf("%s: '%s' is up to date\n", applet_name, np->n_name); 2192 printf("%s: '%s' is up to date\n", applet_name, np->n_name);
2190 } 2193
2191 free(allsrc); 2194 free(allsrc);
2192 free(dedup); 2195 free(dedup);
2193 return estat; 2196 return estat;
diff --git a/testsuite/make.tests b/testsuite/make.tests
index f52770438..7bb736ade 100755
--- a/testsuite/make.tests
+++ b/testsuite/make.tests
@@ -397,6 +397,45 @@ target:
397 : hash # hash 397 : hash # hash
398' 398'
399 399
400# Austin Group defect report 875 clarifies certain aspects of the
401# behaviour of inference rules. Study of this resulted in a number
402# of changes to pdpmake. Since the issue at hand involves the use
403# of chained inference rules it doesn't affect POSIX mode.
404mkdir make.tempdir && cd make.tempdir || exit 1
405touch test.j test.k
406testing "make proper handling of inference rules 1" \
407 "make -f -" \
408 ".j.l\n" "" '
409.SUFFIXES: .j .k .l
410.j.l:
411 @echo .j.l
412.k.l:
413 @echo .k.l
414test.l: test.k
415test.j:
416test.k:
417'
418cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
419
420# The actual test in the above-mentioned defect report was actually
421# more demanding. It used the suffixes '.a .b .c'. This results in
422# the built-in '.c.a' inference rule being introduced into the mix.
423mkdir make.tempdir && cd make.tempdir || exit 1
424touch test.a test.b
425testing "make proper handling of inference rules 2" \
426 "make -f -" \
427 ".a.c\n" "" '
428.SUFFIXES: .a .b .c
429.a.c:
430 @echo .a.c
431.b.c:
432 @echo .b.c
433test.c: test.b
434test.a:
435test.b:
436'
437cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
438
400# Skip duplicate entries in $? and $^ 439# Skip duplicate entries in $? and $^
401mkdir make.tempdir && cd make.tempdir || exit 1 440mkdir make.tempdir && cd make.tempdir || exit 1
402touch -t 202206171200 file1 file3 441touch -t 202206171200 file1 file3