diff options
author | Ron Yorston <rmy@pobox.com> | 2022-10-18 15:00:36 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2022-10-18 15:00:36 +0100 |
commit | 92a127e9f96598b86a4327b70783b9769eaa94fe (patch) | |
tree | 16405c528c5d5712fc1784dfdb5477567592d201 | |
parent | b749a2c0eb47b648805500c23ffbe4550e976a57 (diff) | |
download | busybox-w32-92a127e9f96598b86a4327b70783b9769eaa94fe.tar.gz busybox-w32-92a127e9f96598b86a4327b70783b9769eaa94fe.tar.bz2 busybox-w32-92a127e9f96598b86a4327b70783b9769eaa94fe.zip |
make: support $+ and $^ as POSIX 202X features
Austin Group defect reports 514 and 1520 have both been accepted.
Together these introduce the internal macros $+ and $^:
- $+ lists all prerequisites, with duplicates retained;
- $^ lists all prerequisites, with duplicates removed.
$^ had already been implemented as a non-POSIX extension, it now
becomes a POSIX 202X extension. $+ has been added as a POSIX
202X extension.
Neither of the above defect reports mentions how $? should handle
duplicate prerequisites. In POSIX mode duplicates are retained.
Removal of duplicates is implemented as a non-POSIX extension to
match existing practice in other versions of make.
-rw-r--r-- | miscutils/make.c | 33 | ||||
-rwxr-xr-x | testsuite/make.tests | 12 |
2 files changed, 31 insertions, 14 deletions
diff --git a/miscutils/make.c b/miscutils/make.c index 21d0ede51..8e3778461 100644 --- a/miscutils/make.c +++ b/miscutils/make.c | |||
@@ -1927,15 +1927,17 @@ touch(struct name *np) | |||
1927 | 1927 | ||
1928 | static int | 1928 | static int |
1929 | make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc, | 1929 | make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc, |
1930 | struct name *implicit) | 1930 | char *dedup, struct name *implicit) |
1931 | { | 1931 | { |
1932 | int estat = 0; // 0 exit status is success | 1932 | int estat = 0; // 0 exit status is success |
1933 | char *name, *member = NULL, *base; | 1933 | char *name, *member = NULL, *base; |
1934 | 1934 | ||
1935 | name = splitlib(np->n_name, &member); | 1935 | name = splitlib(np->n_name, &member); |
1936 | setmacro("?", oodate, 0 | M_VALID); | 1936 | setmacro("?", oodate, 0 | M_VALID); |
1937 | if (!posix) | 1937 | if (!posix) { |
1938 | setmacro("^", allsrc, 0 | M_VALID); | 1938 | setmacro("+", allsrc, 0 | M_VALID); |
1939 | setmacro("^", dedup, 0 | M_VALID); | ||
1940 | } | ||
1939 | setmacro("%", member, 0 | M_VALID); | 1941 | setmacro("%", member, 0 | M_VALID); |
1940 | setmacro("@", name, 0 | M_VALID); | 1942 | setmacro("@", name, 0 | M_VALID); |
1941 | if (implicit) { | 1943 | if (implicit) { |
@@ -1993,6 +1995,7 @@ make(struct name *np, int level) | |||
1993 | struct cmd *sc_cmd = NULL; // commands for single-colon rule | 1995 | struct cmd *sc_cmd = NULL; // commands for single-colon rule |
1994 | char *oodate = NULL; | 1996 | char *oodate = NULL; |
1995 | char *allsrc = NULL; | 1997 | char *allsrc = NULL; |
1998 | char *dedup = NULL; | ||
1996 | struct timespec dtim = {1, 0}; | 1999 | struct timespec dtim = {1, 0}; |
1997 | bool didsomething = 0; | 2000 | bool didsomething = 0; |
1998 | bool estat = 0; // 0 exit status is success | 2001 | bool estat = 0; // 0 exit status is success |
@@ -2080,17 +2083,17 @@ make(struct name *np, int level) | |||
2080 | // Make prerequisite | 2083 | // Make prerequisite |
2081 | estat |= make(dp->d_name, level + 1); | 2084 | estat |= make(dp->d_name, level + 1); |
2082 | 2085 | ||
2083 | // Make strings of out-of-date prerequisites (for $?) | 2086 | // Make strings of out-of-date prerequisites (for $?), |
2084 | // and all prerequisites (for $^). But not if we were | 2087 | // all prerequisites (for $+) and deduplicated prerequisites |
2085 | // invoked with -q. | 2088 | // (for $^). But not if we were invoked with -q. |
2086 | if (!quest | 2089 | if (!quest) { |
2087 | // Skip duplicate entries. | ||
2088 | && (posix || !(dp->d_name->n_flag & N_MARK)) | ||
2089 | ) { | ||
2090 | if (timespec_le(&np->n_tim, &dp->d_name->n_tim)) { | 2090 | if (timespec_le(&np->n_tim, &dp->d_name->n_tim)) { |
2091 | oodate = xappendword(oodate, dp->d_name->n_name); | 2091 | if (posix || !(dp->d_name->n_flag & N_MARK)) |
2092 | oodate = xappendword(oodate, dp->d_name->n_name); | ||
2092 | } | 2093 | } |
2093 | allsrc = xappendword(allsrc, dp->d_name->n_name); | 2094 | allsrc = xappendword(allsrc, dp->d_name->n_name); |
2095 | if (!(dp->d_name->n_flag & N_MARK)) | ||
2096 | dedup = xappendword(dedup, dp->d_name->n_name); | ||
2094 | dp->d_name->n_flag |= N_MARK; | 2097 | dp->d_name->n_flag |= N_MARK; |
2095 | } | 2098 | } |
2096 | dtim = *timespec_max(&dtim, &dp->d_name->n_tim); | 2099 | dtim = *timespec_max(&dtim, &dp->d_name->n_tim); |
@@ -2099,7 +2102,7 @@ make(struct name *np, int level) | |||
2099 | if (!quest && ((np->n_flag & N_PHONY) || | 2102 | if (!quest && ((np->n_flag & N_PHONY) || |
2100 | timespec_le(&np->n_tim, &dtim))) { | 2103 | timespec_le(&np->n_tim, &dtim))) { |
2101 | if (estat == 0) { | 2104 | if (estat == 0) { |
2102 | estat = make1(np, rp->r_cmd, oodate, allsrc, locdep); | 2105 | estat = make1(np, rp->r_cmd, oodate, allsrc, dedup, locdep); |
2103 | dtim = (struct timespec){1, 0}; | 2106 | dtim = (struct timespec){1, 0}; |
2104 | didsomething = 1; | 2107 | didsomething = 1; |
2105 | } | 2108 | } |
@@ -2107,7 +2110,8 @@ make(struct name *np, int level) | |||
2107 | oodate = NULL; | 2110 | oodate = NULL; |
2108 | } | 2111 | } |
2109 | free(allsrc); | 2112 | free(allsrc); |
2110 | allsrc = NULL; | 2113 | free(dedup); |
2114 | allsrc = dedup = NULL; | ||
2111 | if (locdep) { | 2115 | if (locdep) { |
2112 | rp->r_dep = rp->r_dep->d_next; | 2116 | rp->r_dep = rp->r_dep->d_next; |
2113 | rp->r_cmd = NULL; | 2117 | rp->r_cmd = NULL; |
@@ -2132,7 +2136,7 @@ make(struct name *np, int level) | |||
2132 | if (!doinclude) | 2136 | if (!doinclude) |
2133 | bb_error_msg("nothing to be done for %s", np->n_name); | 2137 | bb_error_msg("nothing to be done for %s", np->n_name); |
2134 | } else { | 2138 | } else { |
2135 | estat = make1(np, sc_cmd, oodate, allsrc, impdep); | 2139 | estat = make1(np, sc_cmd, oodate, allsrc, dedup, impdep); |
2136 | clock_gettime(CLOCK_REALTIME, &np->n_tim); | 2140 | clock_gettime(CLOCK_REALTIME, &np->n_tim); |
2137 | } | 2141 | } |
2138 | } else if (!doinclude) { | 2142 | } else if (!doinclude) { |
@@ -2145,6 +2149,7 @@ make(struct name *np, int level) | |||
2145 | printf("%s: '%s' is up to date\n", applet_name, np->n_name); | 2149 | printf("%s: '%s' is up to date\n", applet_name, np->n_name); |
2146 | } | 2150 | } |
2147 | free(allsrc); | 2151 | free(allsrc); |
2152 | free(dedup); | ||
2148 | return estat; | 2153 | return estat; |
2149 | } | 2154 | } |
2150 | 2155 | ||
diff --git a/testsuite/make.tests b/testsuite/make.tests index 3d0d14dd0..67617f8a2 100755 --- a/testsuite/make.tests +++ b/testsuite/make.tests | |||
@@ -255,6 +255,18 @@ mk: | |||
255 | -include mk | 255 | -include mk |
256 | ' | 256 | ' |
257 | 257 | ||
258 | # $^ skips duplicate prerequisites, $+ doesn't | ||
259 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
260 | touch file1 file2 file3 | ||
261 | testing "make skip duplicate entries in \$^ but not \$+" \ | ||
262 | "make -f -" \ | ||
263 | "file1 file2 file3\nfile1 file2 file2 file3 file3\n" "" ' | ||
264 | target: file1 file2 file2 file3 file3 | ||
265 | @echo $^ | ||
266 | @echo $+ | ||
267 | ' | ||
268 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
269 | |||
258 | # Nested macro expansion is allowed. This should be compatible | 270 | # Nested macro expansion is allowed. This should be compatible |
259 | # with other implementations. | 271 | # with other implementations. |
260 | testing "make nested macro expansion" \ | 272 | testing "make nested macro expansion" \ |