aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-10-23 16:17:12 +0100
committerRon Yorston <rmy@pobox.com>2023-10-23 16:17:12 +0100
commitd6b76411684d9cc7a676e98bd9f39daecfe8af36 (patch)
treeb3a916bdbad2b229b8714f79274d54c75dd8c929
parent87a3ddc0620fb3ff022663bf2241b92b483e3cf0 (diff)
downloadbusybox-w32-d6b76411684d9cc7a676e98bd9f39daecfe8af36.tar.gz
busybox-w32-d6b76411684d9cc7a676e98bd9f39daecfe8af36.tar.bz2
busybox-w32-d6b76411684d9cc7a676e98bd9f39daecfe8af36.zip
make: fix detection of target rules
The presence of an equal sign in an inline command on a target rule caused the line to be detected as a macro assignment. For example: target:; @echo a = $(a) Rearrange input parsing so target rules are detected before macro assignments. This is made more complex by having to allow for the ':=', '::=' and ':::=' assignment operators. (And for targets containing colons on Windows.) Costs 240-248 bytes.
-rw-r--r--miscutils/make.c335
-rwxr-xr-xtestsuite/make.tests8
2 files changed, 191 insertions, 152 deletions
diff --git a/miscutils/make.c b/miscutils/make.c
index b6103bb58..695f77fa6 100644
--- a/miscutils/make.c
+++ b/miscutils/make.c
@@ -438,8 +438,13 @@ check_name(const char *name)
438{ 438{
439 const char *s; 439 const char *s;
440 440
441 if (!posix) 441 if (!posix) {
442 for (s = name; *s; ++s) {
443 if (*s == '=')
444 return FALSE;
445 }
442 return TRUE; 446 return TRUE;
447 }
443 448
444 for (s = name; *s; ++s) { 449 for (s = name; *s; ++s) {
445#if ENABLE_PLATFORM_MINGW32 450#if ENABLE_PLATFORM_MINGW32
@@ -1157,44 +1162,55 @@ modify_words(const char *val, int modifier, size_t lenf, size_t lenr,
1157} 1162}
1158 1163
1159/* 1164/*
1160 * Return a pointer to the next instance of a given character. Macro 1165 * Try to detect a target rule by searching for a colon that isn't part
1161 * expansions are skipped so the ':' and '=' in $(VAR:.s1=.s2) aren't 1166 * of a macro assignment. Macros must have been expanded already. Return
1162 * detected as separators for rules or macro definitions. 1167 * a pointer to the colon or NULL.
1163 */ 1168 */
1164static char * 1169static char *
1165find_char(const char *str, int c) 1170find_colon(char *p)
1166{ 1171{
1167 const char *s; 1172 char *q;
1168 1173
1169 for (s = skip_macro(str); *s; s = skip_macro(s + 1)) { 1174#if ENABLE_PLATFORM_MINGW32
1170 if (*s == c) 1175 for (q = p; (q = strchr(q, ':')); ++q) {
1171 return (char *)s; 1176 if (posix && !(pragma & P_WINDOWS))
1177 break;
1178 if (q[1] != '/')
1179 break;
1180 }
1181 if (q != NULL) {
1182#else
1183 if ((q = strchr(p, ':')) != NULL) {
1184#endif
1185 // Skip ':=', '::=' and ':::=' macro assignments
1186 if (
1187 // '::=' and ':::=' are from POSIX 202X.
1188 !(!POSIX_2017 && q[1] == ':' && q[2] == ':' && q[3] == '=') &&
1189 !(!POSIX_2017 && q[1] == ':' && q[2] == '=') &&
1190 // ':=' is a non-POSIX extension
1191 !(!posix && q[1] == '=')
1192 )
1193 return q;
1172 } 1194 }
1173 return NULL; 1195 return NULL;
1174} 1196}
1175 1197
1176#if ENABLE_PLATFORM_MINGW32
1177/* 1198/*
1178 * Ignore colons in targets of the form c:/path when looking for a 1199 * Return a pointer to the next instance of a given character. Macro
1179 * target rule. 1200 * expansions are skipped so the ':' and '=' in $(VAR:.s1=.s2) aren't
1201 * detected as separators for rules or macro definitions.
1180 */ 1202 */
1181static char * 1203static char *
1182find_colon(const char *str) 1204find_char(const char *str, int c)
1183{ 1205{
1184 const char *s = str; 1206 const char *s;
1185 1207
1186 while ((s = find_char(s, ':'))) { 1208 for (s = skip_macro(str); *s; s = skip_macro(s + 1)) {
1187 if (posix && !(pragma & P_WINDOWS)) 1209 if (*s == c)
1188 break; 1210 return (char *)s;
1189 if (s[1] != '/')
1190 break;
1191 ++s;
1192 } 1211 }
1193 return (char *)s; 1212 return NULL;
1194} 1213}
1195#else
1196# define find_colon(s) find_char(s, ':')
1197#endif
1198 1214
1199/* 1215/*
1200 * Recursively expand any macros in str to an allocated string. 1216 * Recursively expand any macros in str to an allocated string.
@@ -1881,7 +1897,147 @@ input(FILE *fd, int ilevel)
1881 goto end_loop; 1897 goto end_loop;
1882 } 1898 }
1883 1899
1884 // Check for a macro definition 1900 // Check for target rule
1901 a = p = expanded = expand_macros(str, FALSE);
1902 if ((q = find_colon(p)) != NULL) {
1903 // All tokens before ':' must be valid targets
1904 *q = '\0';
1905 while ((a = gettok(&p)) != NULL && is_valid_target(a))
1906 ;
1907 }
1908 free(expanded);
1909
1910 if (a == NULL) {
1911 // Looks like a target rule
1912 p = expanded = expand_macros(str, FALSE);
1913
1914 // Look for colon separator
1915 q = find_colon(p);
1916 if (q == NULL)
1917 error("expected separator");
1918
1919 *q++ = '\0'; // Separate targets and prerequisites
1920
1921 // Double colon
1922 dbl = !posix && *q == ':';
1923 if (dbl)
1924 q++;
1925
1926 // Look for semicolon separator
1927 cp = NULL;
1928 s = strchr(q, ';');
1929 if (s) {
1930 *s = '\0';
1931 // Retrieve command from copy of line
1932 if ((p = find_char(copy, ':')) && (p = strchr(p, ';')))
1933 newcmd(&cp, process_command(p + 1));
1934 }
1935 semicolon_cmd = cp != NULL;
1936
1937 // Create list of prerequisites
1938 dp = NULL;
1939 while (((p = gettok(&q)) != NULL)) {
1940 char *newp = NULL;
1941
1942 if (!posix) {
1943 // Allow prerequisites of form library(member1 member2).
1944 // Leading and trailing spaces in the brackets are skipped.
1945 if (!lib) {
1946 s = strchr(p, '(');
1947 if (s && !ends_with_bracket(s) && strchr(q, ')')) {
1948 // Looks like an unterminated archive member
1949 // with a terminator later on the line.
1950 lib = p;
1951 if (s[1] != '\0') {
1952 p = newp = auto_concat(lib, ")");
1953 s[1] = '\0';
1954 } else {
1955 continue;
1956 }
1957 }
1958 } else if (ends_with_bracket(p)) {
1959 if (*p != ')')
1960 p = newp = auto_concat(lib, p);
1961 lib = NULL;
1962 if (newp == NULL)
1963 continue;
1964 } else {
1965 p = newp = auto_string(xasprintf("%s%s)", lib, p));
1966 }
1967 }
1968
1969 // If not in POSIX mode expand wildcards in the name.
1970 nfile = 1;
1971 files = &p;
1972 if (!posix && wildcard(p, &gd)) {
1973 nfile = gd.gl_pathc;
1974 files = gd.gl_pathv;
1975 }
1976 for (i = 0; i < nfile; ++i) {
1977 if (!POSIX_2017 && strcmp(files[i], ".WAIT") == 0)
1978 continue;
1979 np = newname(files[i]);
1980 newdep(&dp, np);
1981 }
1982 if (files != &p)
1983 globfree(&gd);
1984 free(newp);
1985 }
1986 lib = NULL;
1987
1988 // Create list of commands
1989 startno = dispno;
1990 while ((str2 = readline(fd)) && *str2 == '\t') {
1991 newcmd(&cp, process_command(str2));
1992 free(str2);
1993 }
1994 dispno = startno;
1995
1996 // Create target names and attach rule to them
1997 q = expanded;
1998 count = 0;
1999 seen_inference = FALSE;
2000 while ((p = gettok(&q)) != NULL) {
2001 // If not in POSIX mode expand wildcards in the name.
2002 nfile = 1;
2003 files = &p;
2004 if (!posix && wildcard(p, &gd)) {
2005 nfile = gd.gl_pathc;
2006 files = gd.gl_pathv;
2007 }
2008 for (i = 0; i < nfile; ++i) {
2009 int ttype = target_type(files[i]);
2010
2011 np = newname(files[i]);
2012 if (ttype != T_NORMAL) {
2013 if (ttype == T_INFERENCE && posix) {
2014 if (semicolon_cmd)
2015 error_in_inference_rule("'; command'");
2016 seen_inference = TRUE;
2017 }
2018 np->n_flag |= N_SPECIAL;
2019 } else if (!firstname) {
2020 firstname = np;
2021 }
2022 addrule(np, dp, cp, dbl);
2023 count++;
2024 }
2025 if (files != &p)
2026 globfree(&gd);
2027 }
2028 if (seen_inference && count != 1)
2029 error_in_inference_rule("multiple targets");
2030
2031 // Prerequisites and commands will be unused if there were
2032 // no targets. Avoid leaking memory.
2033 if (count == 0) {
2034 freedeps(dp);
2035 freecmds(cp);
2036 }
2037 goto end_loop;
2038 }
2039
2040 // If we get here it must be a macro definition
1885 q = find_char(str, '='); 2041 q = find_char(str, '=');
1886 if (q != NULL) { 2042 if (q != NULL) {
1887 int level = (useenv || fd == NULL) ? 4 : 3; 2043 int level = (useenv || fd == NULL) ? 4 : 3;
@@ -1966,135 +2122,10 @@ input(FILE *fd, int ilevel)
1966 } 2122 }
1967 setmacro(a, q, level); 2123 setmacro(a, q, level);
1968 free(newq); 2124 free(newq);
1969 goto end_loop; 2125 } else {
1970 } 2126 error("expected macro definition");
1971
1972 // If we get here it must be a target rule
1973 p = expanded = expand_macros(str, FALSE);
1974
1975 // Look for colon separator
1976 q = find_colon(p);
1977 if (q == NULL)
1978 error("expected separator");
1979
1980 *q++ = '\0'; // Separate targets and prerequisites
1981
1982 // Double colon
1983 dbl = !posix && *q == ':';
1984 if (dbl)
1985 q++;
1986
1987 // Look for semicolon separator
1988 cp = NULL;
1989 s = strchr(q, ';');
1990 if (s) {
1991 *s = '\0';
1992 // Retrieve command from copy of line
1993 if ((p = find_colon(copy)) && (p = strchr(p, ';')))
1994 newcmd(&cp, process_command(p + 1));
1995 }
1996 semicolon_cmd = cp != NULL;
1997
1998 // Create list of prerequisites
1999 dp = NULL;
2000 while (((p = gettok(&q)) != NULL)) {
2001 char *newp = NULL;
2002
2003 if (!posix) {
2004 // Allow prerequisites of form library(member1 member2).
2005 // Leading and trailing spaces in the brackets are skipped.
2006 if (!lib) {
2007 s = strchr(p, '(');
2008 if (s && !ends_with_bracket(s) && strchr(q, ')')) {
2009 // Looks like an unterminated archive member
2010 // with a terminator later on the line.
2011 lib = p;
2012 if (s[1] != '\0') {
2013 p = newp = auto_concat(lib, ")");
2014 s[1] = '\0';
2015 } else {
2016 continue;
2017 }
2018 }
2019 } else if (ends_with_bracket(p)) {
2020 if (*p != ')')
2021 p = newp = auto_concat(lib, p);
2022 lib = NULL;
2023 if (newp == NULL)
2024 continue;
2025 } else {
2026 p = newp = auto_string(xasprintf("%s%s)", lib, p));
2027 }
2028 }
2029
2030 // If not in POSIX mode expand wildcards in the name.
2031 nfile = 1;
2032 files = &p;
2033 if (!posix && wildcard(p, &gd)) {
2034 nfile = gd.gl_pathc;
2035 files = gd.gl_pathv;
2036 }
2037 for (i = 0; i < nfile; ++i) {
2038 if (!POSIX_2017 && strcmp(files[i], ".WAIT") == 0)
2039 continue;
2040 np = newname(files[i]);
2041 newdep(&dp, np);
2042 }
2043 if (files != &p)
2044 globfree(&gd);
2045 free(newp);
2046 } 2127 }
2047 lib = NULL;
2048 2128
2049 // Create list of commands
2050 startno = dispno;
2051 while ((str2 = readline(fd)) && *str2 == '\t') {
2052 newcmd(&cp, process_command(str2));
2053 free(str2);
2054 }
2055 dispno = startno;
2056
2057 // Create target names and attach rule to them
2058 q = expanded;
2059 count = 0;
2060 seen_inference = FALSE;
2061 while ((p = gettok(&q)) != NULL) {
2062 // If not in POSIX mode expand wildcards in the name.
2063 nfile = 1;
2064 files = &p;
2065 if (!posix && wildcard(p, &gd)) {
2066 nfile = gd.gl_pathc;
2067 files = gd.gl_pathv;
2068 }
2069 for (i = 0; i < nfile; ++i) {
2070 int ttype = target_type(files[i]);
2071
2072 np = newname(files[i]);
2073 if (ttype != T_NORMAL) {
2074 if (ttype == T_INFERENCE && posix) {
2075 if (semicolon_cmd)
2076 error_in_inference_rule("'; command'");
2077 seen_inference = TRUE;
2078 }
2079 np->n_flag |= N_SPECIAL;
2080 } else if (!firstname) {
2081 firstname = np;
2082 }
2083 addrule(np, dp, cp, dbl);
2084 count++;
2085 }
2086 if (files != &p)
2087 globfree(&gd);
2088 }
2089 if (seen_inference && count != 1)
2090 error_in_inference_rule("multiple targets");
2091
2092 // Prerequisites and commands will be unused if there were
2093 // no targets. Avoid leaking memory.
2094 if (count == 0) {
2095 freedeps(dp);
2096 freecmds(cp);
2097 }
2098 end_loop: 2129 end_loop:
2099 free(str1); 2130 free(str1);
2100 dispno = lineno; 2131 dispno = lineno;
diff --git a/testsuite/make.tests b/testsuite/make.tests
index 60bb78406..3c2aa5cf5 100755
--- a/testsuite/make.tests
+++ b/testsuite/make.tests
@@ -94,6 +94,14 @@ target:
94 @exit 42 94 @exit 42
95' 95'
96 96
97# An equal sign in a command on a target rule was detected as a
98# macro assignment.
99testing "make equal sign in inline command" \
100 "make -f -" "a = a\n" "" '
101a = a
102target:;@echo a = $(a)
103'
104
97# A macro created using ::= remembers it's of type immediate-expansion. 105# A macro created using ::= remembers it's of type immediate-expansion.
98# Immediate expansion also occurs when += is used to append to such a macro. 106# Immediate expansion also occurs when += is used to append to such a macro.
99testing "make appending to immediate-expansion macro" \ 107testing "make appending to immediate-expansion macro" \