| /* Variable expansion functions for GNU Make. | |
| Copyright (C) 1988-2025 Free Software Foundation, Inc. | |
| This file is part of GNU Make. | |
| GNU Make is free software; you can redistribute it and/or modify it under the | |
| terms of the GNU General Public License as published by the Free Software | |
| Foundation; either version 3 of the License, or (at your option) any later | |
| version. | |
| GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY | |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License along with | |
| this program. If not, see <https://www.gnu.org/licenses/>. */ | |
| #include "makeint.h" | |
| #include <assert.h> | |
| #include "commands.h" | |
| #include "debug.h" | |
| #include "filedef.h" | |
| #include "job.h" | |
| #include "rule.h" | |
| #include "variable.h" | |
| #include "warning.h" | |
| /* Initially, any errors reported when expanding strings will be reported | |
| against the file where the error appears. */ | |
| const floc **expanding_var = &reading_file; | |
| /* The next two describe the variable output buffer. | |
| This buffer is used to hold the variable-expansion of a line of the | |
| makefile. It is made bigger with realloc whenever it is too small. | |
| variable_buffer_length is the size currently allocated. | |
| variable_buffer is the address of the buffer. | |
| For efficiency, it's guaranteed that the buffer will always have | |
| VARIABLE_BUFFER_ZONE extra bytes allocated. This allows you to add a few | |
| extra chars without having to call a function. Note you should never use | |
| these bytes unless you're _sure_ you have room (you know when the buffer | |
| length was last checked. */ | |
| #define VARIABLE_BUFFER_ZONE 5 | |
| static size_t variable_buffer_length; | |
| char *variable_buffer; | |
| /* Append LENGTH chars of STRING at PTR which must point into variable_buffer. | |
| The buffer will always be kept nul-terminated. | |
| The updated pointer into the buffer is returned as the value. Thus, the | |
| value returned by each call to variable_buffer_output should be the first | |
| argument to the following call. */ | |
| char * | |
| variable_buffer_output (char *ptr, const char *string, size_t length) | |
| { | |
| size_t newlen = length + (ptr - variable_buffer); | |
| assert (ptr >= variable_buffer); | |
| assert (ptr < variable_buffer + variable_buffer_length); | |
| if (newlen + VARIABLE_BUFFER_ZONE + 1 > variable_buffer_length) | |
| { | |
| size_t offset = ptr - variable_buffer; | |
| variable_buffer_length = (newlen + 100 > 2 * variable_buffer_length | |
| ? newlen + 100 | |
| : 2 * variable_buffer_length); | |
| variable_buffer = xrealloc (variable_buffer, variable_buffer_length + 1); | |
| ptr = variable_buffer + offset; | |
| } | |
| ptr = mempcpy (ptr, string, length); | |
| *ptr = '\0'; | |
| return ptr; | |
| } | |
| /* Return a pointer to the beginning of the variable buffer. | |
| This is called from main() and it should never be null afterward. */ | |
| char * | |
| initialize_variable_output () | |
| { | |
| /* If we don't have a variable output buffer yet, get one. */ | |
| if (!variable_buffer) | |
| { | |
| variable_buffer_length = 200; | |
| variable_buffer = xmalloc (variable_buffer_length); | |
| } | |
| variable_buffer[0] = '\0'; | |
| return variable_buffer; | |
| } | |
| /* Install a new variable_buffer context, returning the current one for | |
| safe-keeping. */ | |
| void | |
| install_variable_buffer (char **bufp, size_t *lenp) | |
| { | |
| *bufp = variable_buffer; | |
| *lenp = variable_buffer_length; | |
| variable_buffer = NULL; | |
| initialize_variable_output (); | |
| } | |
| /* Free the current variable_buffer and restore a previously-saved one. | |
| */ | |
| void | |
| restore_variable_buffer (char *buf, size_t len) | |
| { | |
| free (variable_buffer); | |
| variable_buffer = buf; | |
| variable_buffer_length = len; | |
| } | |
| /* Restore a previously-saved variable_buffer context, and return the | |
| current one. | |
| */ | |
| char * | |
| swap_variable_buffer (char *buf, size_t len) | |
| { | |
| char *p = variable_buffer; | |
| variable_buffer = buf; | |
| variable_buffer_length = len; | |
| return p; | |
| } | |
| /* Recursively expand V. The returned string is malloc'd. */ | |
| static char *allocated_variable_append (const struct variable *v); | |
| char * | |
| recursively_expand_for_file (struct variable *v, struct file *file) | |
| { | |
| char *value; | |
| const floc *this_var; | |
| const floc **saved_varp; | |
| struct variable_set_list *savev = 0; | |
| int set_reading = 0; | |
| size_t nl = strlen (v->name); | |
| struct variable *parent = NULL; | |
| /* If we're expanding to put into the environment of a shell function then | |
| ignore any recursion issues: for backward-compatibility we will use | |
| the value of the environment variable we were started with. */ | |
| if (v->expanding && env_recursion) | |
| { | |
| char **ep; | |
| DB (DB_VERBOSE, | |
| (_("%s:%lu: not recursively expanding %s to export to shell function\n"), | |
| v->fileinfo.filenm, v->fileinfo.lineno, v->name)); | |
| /* We could create a hash for the original environment for speed, but a | |
| reasonably written makefile shouldn't hit this situation... */ | |
| for (ep = environ; *ep != 0; ++ep) | |
| if (strncmp (*ep, v->name, nl) == 0 && (*ep)[nl] == '=') | |
| return xstrdup ((*ep) + nl + 1); | |
| /* If there's nothing in the parent environment, use the empty string. | |
| This isn't quite correct since the variable should not exist at all, | |
| but getting that to work would be involved. */ | |
| return xstrdup (""); | |
| } | |
| /* Don't install a new location if this location is empty. | |
| This can happen for command-line variables, builtin variables, etc. */ | |
| saved_varp = expanding_var; | |
| if (v->fileinfo.filenm) | |
| { | |
| this_var = &v->fileinfo; | |
| expanding_var = &this_var; | |
| } | |
| /* If we have no other file-reading context, use the variable's context. */ | |
| if (!reading_file) | |
| { | |
| set_reading = 1; | |
| reading_file = &v->fileinfo; | |
| } | |
| if (v->expanding) | |
| { | |
| if (!v->exp_count) | |
| /* Expanding V causes infinite recursion. Lose. */ | |
| OS (fatal, *expanding_var, | |
| _("recursive variable '%s' references itself (eventually)"), | |
| v->name); | |
| --v->exp_count; | |
| } | |
| if (file) | |
| install_file_context (file, &savev, NULL); | |
| v->expanding = 1; | |
| if (v->append) | |
| { | |
| /* Find a parent definition which is marked override. */ | |
| struct variable_set_list *sl; | |
| for (sl = current_variable_set_list; sl && !parent; sl = sl->next) | |
| { | |
| struct variable *vp = lookup_variable_in_set (v->name, nl, sl->set); | |
| if (vp && vp != v && vp->origin == o_override) | |
| parent = vp; | |
| } | |
| } | |
| if (parent) | |
| /* PARENT is an override, V is appending. If V is also an override: | |
| override hello := first | |
| al%: override hello += second | |
| Then construct the value from its appended parts in the parent sets. | |
| Else if V is not an override: | |
| override hello := first | |
| al%: hello += second | |
| Then ignore the value of V and use the value of PARENT. */ | |
| value = v->origin == o_override | |
| ? allocated_variable_append (v) | |
| : xstrdup (parent->value); | |
| else if (v->origin == o_command || v->origin == o_env_override) | |
| /* Avoid appending to a pattern-specific variable, unless the origin of this | |
| pattern-specific variable beats or equals the origin of one of the parent | |
| definitions of this variable. | |
| This is needed, because if there is a command line definition or an env | |
| override, then the value defined in the makefile should only be appended | |
| in the case of a file override. | |
| In the presence of command line definition or env override and absence of | |
| makefile override, the value should be expanded, rather than appended. In | |
| this case, at parse time record_target_var already set the value of this | |
| pattern-specific variable to the value defined on the command line or to | |
| the env override value. | |
| User provided a command line definition or an env override. | |
| PARENT does not have an override directive, so ignore it. */ | |
| value = allocated_expand_string (v->value); | |
| else if (v->append) | |
| /* Construct the value from its appended parts in the parent sets. */ | |
| value = allocated_variable_append (v); | |
| else | |
| /* A definition without appending. */ | |
| value = allocated_expand_string (v->value); | |
| v->expanding = 0; | |
| if (set_reading) | |
| reading_file = 0; | |
| if (file) | |
| restore_file_context (savev, NULL); | |
| expanding_var = saved_varp; | |
| return value; | |
| } | |
| /* Expand a simple reference to variable NAME, which is LENGTH chars long. | |
| The result is written to PTR which must point into the variable_buffer. | |
| Returns a pointer to the new end of the variable_buffer. */ | |
| char * | |
| expand_variable_output (char *ptr, const char *name, size_t length) | |
| { | |
| struct variable *v; | |
| unsigned int recursive; | |
| char *value; | |
| v = lookup_variable (name, length); | |
| if (!v) | |
| warn_undefined (name, length); | |
| /* If there's no variable by that name or it has no value, stop now. */ | |
| if (!v || (v->value[0] == '\0' && !v->append)) | |
| return ptr; | |
| /* Remember this since expansion could change it. */ | |
| recursive = v->recursive; | |
| value = recursive ? recursively_expand (v) : v->value; | |
| ptr = variable_buffer_output (ptr, value, strlen (value)); | |
| if (recursive) | |
| free (value); | |
| return ptr; | |
| } | |
| /* Expand a simple reference to variable NAME, which is LENGTH chars long. | |
| The result is written to BUF which must point into the variable_buffer. | |
| If BUF is NULL, start at the beginning of the current variable_buffer. | |
| Returns a pointer to the START of the expanded value of the variable. | |
| The returned value is located inside variable_buffer. | |
| The returned value is valid until the next call to one of the functions | |
| which use variable_buffer. expand_variable_buf may reallocate | |
| variable_buffer and render the passed-in BUF invalid. */ | |
| char * | |
| expand_variable_buf (char *buf, const char *name, size_t length) | |
| { | |
| size_t offs; | |
| if (!buf) | |
| buf = initialize_variable_output (); | |
| assert (buf >= variable_buffer); | |
| assert (buf < variable_buffer + variable_buffer_length); | |
| offs = buf - variable_buffer; | |
| expand_variable_output (buf, name, length); | |
| return variable_buffer + offs; | |
| } | |
| /* Expand a simple reference to variable NAME, which is LENGTH chars long. | |
| Returns an allocated buffer containing the value. */ | |
| char * | |
| allocated_expand_variable (const char *name, size_t length) | |
| { | |
| char *obuf; | |
| size_t olen; | |
| install_variable_buffer (&obuf, &olen); | |
| expand_variable_output (variable_buffer, name, length); | |
| return swap_variable_buffer (obuf, olen); | |
| } | |
| /* Expand a simple reference to variable NAME, which is LENGTH chars long. | |
| Error messages refer to the file and line where FILE's commands were found. | |
| Expansion uses FILE's variable set list. | |
| Returns an allocated buffer containing the value. */ | |
| char * | |
| allocated_expand_variable_for_file (const char *name, size_t length, struct file *file) | |
| { | |
| char *result; | |
| struct variable_set_list *savev; | |
| const floc *savef; | |
| if (!file) | |
| return allocated_expand_variable (name, length); | |
| install_file_context (file, &savev, &savef); | |
| result = allocated_expand_variable (name, length); | |
| restore_file_context (savev, savef); | |
| return result; | |
| } | |
| /* Scan STRING for variable references and expansion-function calls. Only | |
| LENGTH bytes of STRING are actually scanned. | |
| If LENGTH is SIZE_MAX, scan until a null byte is found. | |
| Write the results to BUF, which must point into variable_buffer. If | |
| BUF is NULL, start at the beginning of the current variable_buffer. | |
| Return a pointer to BUF, or to the beginning of the new buffer if BUF is | |
| NULL. | |
| */ | |
| char * | |
| expand_string_buf (char *buf, const char *string, size_t length) | |
| { | |
| struct variable *v; | |
| const char *p, *p1; | |
| char *save; | |
| char *o; | |
| size_t line_offset; | |
| if (!buf) | |
| buf = initialize_variable_output (); | |
| o = buf; | |
| line_offset = buf - variable_buffer; | |
| if (length == 0) | |
| return variable_buffer; | |
| /* We need a copy of STRING: due to eval, it's possible that it will get | |
| freed as we process it (it might be the value of a variable that's reset | |
| for example). Also having a nil-terminated string is handy. */ | |
| save = length == SIZE_MAX ? xstrdup (string) : xstrndup (string, length); | |
| p = save; | |
| while (1) | |
| { | |
| /* Copy all following uninteresting chars all at once to the | |
| variable output buffer, and skip them. Uninteresting chars end | |
| at the next $ or the end of the input. */ | |
| p1 = strchr (p, '$'); | |
| o = variable_buffer_output (o, p, p1 != 0 ? (size_t) (p1 - p) : strlen (p) + 1); | |
| if (p1 == 0) | |
| break; | |
| p = p1 + 1; | |
| /* Dispatch on the char that follows the $. */ | |
| switch (*p) | |
| { | |
| case '$': | |
| case '\0': | |
| /* $$ or $ at the end of the string means output one $ to the | |
| variable output buffer. */ | |
| o = variable_buffer_output (o, p1, 1); | |
| break; | |
| case '(': | |
| case '{': | |
| /* $(...) or ${...} is the general case of substitution. */ | |
| { | |
| char openparen = *p; | |
| char closeparen = (openparen == '(') ? ')' : '}'; | |
| const char *beg = p + 1; | |
| char *abeg = NULL; | |
| const char *end, *colon; | |
| if (handle_function (&o, &p)) | |
| break; | |
| /* Is there a variable reference inside the parens or braces? | |
| If so, expand it before expanding the entire reference. */ | |
| end = strchr (beg, closeparen); | |
| if (end == NULL) | |
| /* Unterminated variable reference. */ | |
| O (fatal, *expanding_var, _("unterminated variable reference")); | |
| p1 = lindex (beg, end, '$'); | |
| if (p1 != NULL) | |
| { | |
| /* BEG now points past the opening paren or brace. | |
| Count parens or braces until it is matched. */ | |
| int count = 1; | |
| for (p = beg; *p != '\0'; ++p) | |
| { | |
| if (*p == openparen) | |
| ++count; | |
| else if (*p == closeparen && --count == 0) | |
| break; | |
| } | |
| /* If COUNT is > 0, there were unmatched opening parens | |
| or braces, so we go to the simple case of a variable name | |
| such as '$($(a)'. */ | |
| if (count == 0) | |
| { | |
| /* Expand the name. */ | |
| abeg = expand_argument (beg, p); | |
| beg = abeg; | |
| end = strchr (beg, '\0'); | |
| } | |
| } | |
| else | |
| /* Advance P to the end of this reference. After we are | |
| finished expanding this one, P will be incremented to | |
| continue the scan. */ | |
| p = end; | |
| /* This is not a reference to a built-in function and | |
| any variable references inside are now expanded. | |
| Is the resultant text a substitution reference? */ | |
| colon = lindex (beg, end, ':'); | |
| if (colon) | |
| { | |
| /* This looks like a substitution reference: $(FOO:A=B). */ | |
| const char *subst_beg = colon + 1; | |
| const char *subst_end = lindex (subst_beg, end, '='); | |
| if (subst_end == 0) | |
| /* There is no = in sight. Punt on the substitution | |
| reference and treat this as a variable name containing | |
| a colon, in the code below. */ | |
| colon = 0; | |
| else | |
| { | |
| const char *replace_beg = subst_end + 1; | |
| const char *replace_end = end; | |
| /* Extract the variable name before the colon | |
| and look up that variable. */ | |
| v = lookup_variable (beg, colon - beg); | |
| if (v == 0) | |
| warn_undefined (beg, colon - beg); | |
| /* If the variable is not empty, perform the | |
| substitution. */ | |
| if (v != 0 && *v->value != '\0') | |
| { | |
| char *pattern, *replace, *ppercent, *rpercent; | |
| char *value = (v->recursive | |
| ? recursively_expand (v) | |
| : v->value); | |
| /* Copy the pattern and the replacement. Add in an | |
| extra % at the beginning to use in case there | |
| isn't one in the pattern. */ | |
| pattern = alloca (subst_end - subst_beg + 2); | |
| *(pattern++) = '%'; | |
| memcpy (pattern, subst_beg, subst_end - subst_beg); | |
| pattern[subst_end - subst_beg] = '\0'; | |
| replace = alloca (replace_end - replace_beg + 2); | |
| *(replace++) = '%'; | |
| memcpy (replace, replace_beg, | |
| replace_end - replace_beg); | |
| replace[replace_end - replace_beg] = '\0'; | |
| /* Look for %. Set the percent pointers properly | |
| based on whether we find one or not. */ | |
| ppercent = find_percent (pattern); | |
| if (ppercent) | |
| { | |
| ++ppercent; | |
| rpercent = find_percent (replace); | |
| if (rpercent) | |
| ++rpercent; | |
| } | |
| else | |
| { | |
| ppercent = pattern; | |
| rpercent = replace; | |
| --pattern; | |
| --replace; | |
| } | |
| o = patsubst_expand_pat (o, value, pattern, replace, | |
| ppercent, rpercent); | |
| if (v->recursive) | |
| free (value); | |
| } | |
| } | |
| } | |
| if (colon == 0) | |
| /* This is an ordinary variable reference. | |
| Look up the value of the variable. */ | |
| o = expand_variable_output (o, beg, end - beg); | |
| free (abeg); | |
| } | |
| break; | |
| default: | |
| if (ISSPACE (p[-1])) | |
| break; | |
| /* A $ followed by a random char is a variable reference: | |
| $a is equivalent to $(a). */ | |
| o = expand_variable_output (o, p, 1); | |
| break; | |
| } | |
| if (*p == '\0') | |
| break; | |
| ++p; | |
| } | |
| free (save); | |
| return (variable_buffer + line_offset); | |
| } | |
| /* Expand an argument for an expansion function. | |
| The text starting at STR and ending at END is variable-expanded | |
| into a null-terminated string that is returned as the value. | |
| This is done without clobbering 'variable_buffer' or the current | |
| variable-expansion that is in progress. */ | |
| char * | |
| expand_argument (const char *str, const char *end) | |
| { | |
| char *tmp, *alloc = NULL; | |
| char *r; | |
| if (str == end) | |
| return xstrdup (""); | |
| if (!end || *end == '\0') | |
| return allocated_expand_string (str); | |
| if (end - str + 1 > 1000) | |
| tmp = alloc = xmalloc (end - str + 1); | |
| else | |
| tmp = alloca (end - str + 1); | |
| memcpy (tmp, str, end - str); | |
| tmp[end - str] = '\0'; | |
| r = allocated_expand_string (tmp); | |
| free (alloc); | |
| return r; | |
| } | |
| /* Expand STRING for FILE, into the current variable_buffer. | |
| Error messages refer to the file and line where FILE's commands were found. | |
| Expansion uses FILE's variable set list. */ | |
| char * | |
| expand_string_for_file (const char *string, struct file *file) | |
| { | |
| char *result; | |
| struct variable_set_list *savev; | |
| const floc *savef; | |
| if (!file) | |
| return expand_string (string); | |
| install_file_context (file, &savev, &savef); | |
| result = expand_string (string); | |
| restore_file_context (savev, savef); | |
| return result; | |
| } | |
| /* Like expand_string_for_file, but the returned string is malloc'd. */ | |
| char * | |
| allocated_expand_string_for_file (const char *string, struct file *file) | |
| { | |
| char *obuf; | |
| size_t olen; | |
| install_variable_buffer (&obuf, &olen); | |
| expand_string_for_file (string, file); | |
| return swap_variable_buffer (obuf, olen); | |
| } | |
| /* Like allocated_expand_string, but for += target-specific variables. | |
| First recursively construct the variable value from its appended parts in | |
| any upper variable sets. Then expand the resulting value. */ | |
| static char * | |
| variable_append (const char *name, size_t length, | |
| const struct variable_set_list *set, int local) | |
| { | |
| const struct variable *v; | |
| char *buf = 0; | |
| int nextlocal; | |
| /* If there's nothing left to check, return the empty buffer. */ | |
| if (!set) | |
| return initialize_variable_output (); | |
| /* If this set is local and the next is not a parent, then next is local. */ | |
| nextlocal = local && set->next_is_parent == 0; | |
| /* Try to find the variable in this variable set. */ | |
| v = lookup_variable_in_set (name, length, set->set); | |
| /* If there isn't one, or this one is private, try the set above us. */ | |
| if (!v || (!local && v->private_var)) | |
| return variable_append (name, length, set->next, nextlocal); | |
| /* If this variable type is append, first get any upper values. | |
| If not, initialize the buffer. */ | |
| if (v->append) | |
| buf = variable_append (name, length, set->next, nextlocal); | |
| else | |
| buf = initialize_variable_output (); | |
| /* Append this value to the buffer, and return it. | |
| If we already have a value, first add a space. */ | |
| if (buf > variable_buffer) | |
| buf = variable_buffer_output (buf, " ", 1); | |
| /* Either expand it or copy it, depending. */ | |
| if (! v->recursive) | |
| return variable_buffer_output (buf, v->value, strlen (v->value)); | |
| buf = expand_string_buf (buf, v->value, strlen (v->value)); | |
| return (buf + strlen (buf)); | |
| } | |
| static char * | |
| allocated_variable_append (const struct variable *v) | |
| { | |
| /* Construct the appended variable value. */ | |
| char *obuf; | |
| size_t olen; | |
| install_variable_buffer (&obuf, &olen); | |
| variable_append (v->name, strlen (v->name), current_variable_set_list, 1); | |
| return swap_variable_buffer (obuf, olen); | |
| } |