+2010-11-06 Paul Smith <psmith@gnu.org>
+
+ * variable.c (print_auto_variable): Print auto variables; ignore others.
+ (print_noauto_variable): Print non-auto variables; ignore others.
+ (print_variable_set): Allow the caller to select which type to print.
+ (print_target_variables): Show all the non-auto variables for a target.
+
+ * default.c (install_default_suffix_rules): Initialize recipe_prefix.
+ * rule.c (install_pattern_rule): Ditto.
+ * read.c (record_files): Pass in the current recipe prefix. Remember
+ it in the struct command for these targets.
+ (eval): Remember the value of RECIPEPREFIX when we start parsing.
+ Do not remove recipe prefixes from the recipe here: we'll do it later.
+ * job.c (start_job_command): Remove recipe prefix characters early,
+ before we print the output or chop it up.
+ * file.c (print_file): If recipe_prefix is not standard, reset it
+ in -p output. Assign target variables in -p output as well.
+
+ * commands.c (chop_commands): Max command lines is USHRT_MAX.
+ Set any_recurse as a bitfield.
+ * make.h (USHRT_MAX): Define if not set.
+
+2010-10-27 Paul Smith <psmith@gnu.org>
+
+ * commands.h (struct commands): Rearrange to make better use of
+ memory. Add new recipe_prefix value.
+
+2010-10-26 Paul Smith <psmith@gnu.org>
+
+ * doc/make.texi (Setting): Document the treatment of
+ backslash-newline in variable values.
+ * misc.c (collapse_continuations): Do not collapse multiple
+ backslash-newlines into a single space. Fixes Savannah bug #16670.
+
2010-08-29 Paul Smith <psmith@gnu.org>
* doc/make.texi (Implicit Variables): Document LDLIBS and LOADLIBES.
http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set=custom
+* WARNING: Backward-incompatibility!
+ This version of make adheres to the POSIX backslash/newline handling,
+ introducing the following differences:
+ * Each backslash/newline in a variable value is replaced with a space;
+ multiple consecutive backslash/newlines do not condense into one space.
+ * In recipes, a recipe prefix following a backslash-newlines is removed.
+
* New command line option: --trace enables tracing of targets. When enabled
the recipe to be invoked is printed even if it would otherwise be suppressed
by .SILENT or a "@" prefix character. Also before each recipe is run the
* On failure, the makefile name and linenumber of the recipe that failed are
shown.
+* A .RECIPEPREFIX setting is remembered per-recipe and variables expanded
+ in that recipe also use that recipe prefix setting.
+
+* In -p output, .RECIPEPREFIX settings are shown and all target-specific
+ variables are output as if in a makefile, instead of as comments.
+
\f
Version 3.82
/* Finally, set the corresponding CMDS->lines_flags elements and the
CMDS->any_recurse flag. */
+ if (nlines > USHRT_MAX)
+ fatal (&cmds->fileinfo, _("Recipe has too many lines (%ud)"), nlines);
+
cmds->ncommand_lines = nlines;
cmds->command_lines = lines;
flags |= COMMANDS_RECURSE;
cmds->lines_flags[idx] = flags;
- cmds->any_recurse |= flags & COMMANDS_RECURSE;
+ cmds->any_recurse |= flags & COMMANDS_RECURSE ? 1 : 0;
}
}
\f
while (*s != '\0')
{
const char *end;
+ int bs;
- end = strchr (s, '\n');
- if (end == 0)
- end = s + strlen (s);
+ /* Print one full logical recipe line: find a non-escaped newline. */
+ for (end = s, bs = 0; *end != '\0'; ++end)
+ {
+ if (*end == '\n' && !bs)
+ break;
+
+ bs = *end == '\\' ? !bs : 0;
+ }
printf ("%c%.*s\n", cmd_prefix, (int) (end - s), s);
{
struct floc fileinfo; /* Where commands were defined. */
char *commands; /* Commands text. */
- unsigned int ncommand_lines;/* Number of command lines. */
char **command_lines; /* Commands chopped up into lines. */
char *lines_flags; /* One set of flag bits for each line. */
- int any_recurse; /* Nonzero if any `lines_recurse' elt has */
+ unsigned short ncommand_lines;/* Number of command lines. */
+ char recipe_prefix; /* Recipe prefix for this command set. */
+ unsigned int any_recurse:1; /* Nonzero if any `lines_flags' elt has */
/* the COMMANDS_RECURSE bit set. */
};
static struct pspec default_pattern_rules[] =
{
{ "(%)", "%",
- "$(AR) $(ARFLAGS) $@ $<" },
+ "$(AR) $(ARFLAGS) $@ $<" },
/* The X.out rules are only in BSD's default set because
BSD Make has no null-suffix rules, so `foo.out' and
"copy $< $@" },
#else
{ "%.out", "%",
- "@rm -f $@ \n cp $< $@" },
+ "@rm -f $@ \n cp $< $@" },
#endif
/* Syntax is "ctangle foo.w foo.ch foo.c". */
{ "%.c", "%.w %.ch",
- "$(CTANGLE) $^ $@" },
+ "$(CTANGLE) $^ $@" },
{ "%.tex", "%.w %.ch",
- "$(CWEAVE) $^ $@" },
+ "$(CWEAVE) $^ $@" },
{ 0, 0, 0 }
};
"if f$$search($@) .nes. \"\" then +$(CHECKOUT,v)" },
/* SCCS. */
- /* ain't no SCCS on vms */
+ /* ain't no SCCS on vms */
#else
/* RCS. */
{ "%", "%,v",
- "$(CHECKOUT,v)" },
+ "$(CHECKOUT,v)" },
{ "%", "RCS/%,v",
- "$(CHECKOUT,v)" },
+ "$(CHECKOUT,v)" },
{ "%", "RCS/%",
- "$(CHECKOUT,v)" },
+ "$(CHECKOUT,v)" },
/* SCCS. */
{ "%", "s.%",
- "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" },
+ "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" },
{ "%", "SCCS/s.%",
- "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" },
+ "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" },
#endif /* !VMS */
{ 0, 0, 0 }
};
"$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<",
".w.c",
- "$(CTANGLE) $< - $@", /* The `-' says there is no `.ch' file. */
+ "$(CTANGLE) $< - $@", /* The `-' says there is no `.ch' file. */
".web.p",
"$(TANGLE) $<",
".w.tex",
- "$(CWEAVE) $< - $@", /* The `-' says there is no `.ch' file. */
+ "$(CWEAVE) $< - $@", /* The `-' says there is no `.ch' file. */
".web.tex",
"$(WEAVE) $<",
#ifdef GCC_IS_NATIVE
"CC", "gcc",
# ifdef __MSDOS__
- "CXX", "gpp", /* g++ is an invalid name on MSDOS */
+ "CXX", "gpp", /* g++ is an invalid name on MSDOS */
# else
"CXX", "gcc",
# endif /* __MSDOS__ */
"COFLAGS", "",
"CPP", "$(CC) -E",
-#ifdef CRAY
+#ifdef CRAY
"CF77PPFLAGS", "-P",
"CF77PP", "/lib/cpp",
"CFT", "cft77",
"CF", "cf77",
"FC", "$(CF)",
-#else /* Not CRAY. */
-#ifdef _IBMR2
+#else /* Not CRAY. */
+#ifdef _IBMR2
"FC", "xlf",
#else
-#ifdef __convex__
+#ifdef __convex__
"FC", "fc",
#else
"FC", "f77",
However, there is no way to make implicit rules use them and FC. */
"F77", "$(FC)",
"F77FLAGS", "$(FFLAGS)",
-#endif /* Cray. */
+#endif /* Cray. */
"GET", SCCS_GET,
"LD", "ld",
#ifdef GCC_IS_NATIVE
#endif
"LINT", "lint",
"M2C", "m2c",
-#ifdef pyr
+#ifdef pyr
"PC", "pascal",
#else
-#ifdef CRAY
+#ifdef CRAY
"PC", "PASCAL",
"SEGLDR", "segldr",
#else
"PC", "pc",
-#endif /* CRAY. */
-#endif /* pyr. */
+#endif /* CRAY. */
+#endif /* pyr. */
#ifdef GCC_IS_NATIVE
"YACC", "bison -y",
#else
- "YACC", "yacc", /* Or "bison -y" */
+ "YACC", "yacc", /* Or "bison -y" */
#endif
"MAKEINFO", "makeinfo",
"TEX", "tex",
"PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F",
"LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
-#ifndef NO_MINUS_C_MINUS_O
+#ifndef NO_MINUS_C_MINUS_O
"OUTPUT_OPTION", "-o $@",
#endif
-#ifdef SCCS_GET_MINUS_G
+#ifdef SCCS_GET_MINUS_G
"SCCS_OUTPUT_OPTION", "-G$@",
#endif
struct file *f = enter_file (strcache_add (s[0]));
/* Don't clobber cmds given in a makefile if there were any. */
if (f->cmds == 0)
- {
- f->cmds = xmalloc (sizeof (struct commands));
- f->cmds->fileinfo.filenm = 0;
- f->cmds->commands = s[1];
- f->cmds->command_lines = 0;
- }
+ {
+ f->cmds = xmalloc (sizeof (struct commands));
+ f->cmds->fileinfo.filenm = 0;
+ f->cmds->commands = s[1];
+ f->cmds->command_lines = 0;
+ f->cmds->recipe_prefix = RECIPEPREFIX_DEFAULT;
+ }
}
}
Note that the directory prefix (D), as described in @ref{Implicit Rule
Search, ,Implicit Rule Search Algorithm}, is appended (after
expansion) to all the patterns in the prerequisites list. As an
-example:
+example:@refill
@example
.SECONDEXPANSION:
/tmp/foo.o:
%.o: $$(addsuffix /%.c,foo bar) foo.h
+ @@echo $^
@end example
-The prerequisite list after the secondary expansion and directory
-prefix reconstruction will be @file{/tmp/foo/foo.c /tmp/var/bar/foo.c
-foo.h}. If you are not interested in this reconstruction, you can use
-@code{$$*} instead of @code{%} in the prerequisites list.
+The prerequisite list printed, after the secondary expansion and
+directory prefix reconstruction, will be @file{/tmp/foo/foo.c
+/tmp/bar/foo.c foo.h}. If you are not interested in this
+reconstruction, you can use @code{$$*} instead of @code{%} in the
+prerequisites list.
@node Rules, Recipes, Makefiles, Top
@chapter Writing Rules
are expanded when the line is read to find the actual variable name to use.
There is no limit on the length of the value of a variable except the
-amount of swapping space on the computer. When a variable definition is
-long, it is a good idea to break it into several lines by inserting
-backslash-newline at convenient places in the definition. This will not
-affect the functioning of @code{make}, but it will make the makefile easier
-to read.
+amount of memory on the computer. When a variable definition is long,
+it is a good idea to break it into several lines by inserting
+backslash-newline at convenient places in the definition. This will
+make the makefile easier to read. Every backslash-newline, along with
+any leading whitespace on the following line, will be replaced by a
+single space in the value of the variable.
Most variable names are considered to have the empty string as a value if
you have never set them. Several variables have built-in initial values
const struct file *f = item;
putchar ('\n');
+
+ if (f->cmds && f->cmds->recipe_prefix != cmd_prefix)
+ {
+ fputs (".RECIPEPREFIX = ", stdout);
+ cmd_prefix = f->cmds->recipe_prefix;
+ if (cmd_prefix != RECIPEPREFIX_DEFAULT)
+ putchar (cmd_prefix);
+ putchar ('\n');
+ }
+
+ if (f->variables != 0)
+ print_target_variables (f);
+
if (!f->is_target)
puts (_("# Not a target:"));
printf ("%s:%s", f->name, f->double_colon ? ":" : "");
short int update_status; /* Status of the last attempt to update,
or -1 if none has been made. */
-
enum cmd_state /* State of the commands. */
{ /* Note: It is important that cs_not_started be zero. */
cs_not_started, /* Not yet started. */
child->file->cmds->lines_flags[child->command_line - 1]
|= flags & COMMANDS_RECURSE;
- /* Figure out an argument list from this command line. */
+ /* POSIX requires that a recipe prefix after a backslash-newline should
+ be ignored. Remove it now so the output is correct. */
+ {
+ char prefix = child->file->cmds->recipe_prefix;
+ char *p1, *p2;
+ p1 = p2 = p;
+ while (*p1 != '\0')
+ {
+ *(p2++) = *p1;
+ if (p1[0] == '\n' && p1[1] == prefix)
+ ++p1;
+ ++p1;
+ }
+ *p2 = *p1;
+ }
+ /* Figure out an argument list from this command line. */
{
char *end = 0;
#ifdef VMS
#else
argv = construct_command_argv (p, &end, child->file,
child->file->cmds->lines_flags[child->command_line - 1],
- &child->sh_batch_file);
+ &child->sh_batch_file);
#endif
if (end == NULL)
child->command_ptr = NULL;
static char **
construct_command_argv_internal (char *line, char **restp, char *shell,
char *shellflags, char *ifs, int flags,
- char **batch_filename_ptr)
+ char **batch_filename_p)
{
#ifdef __MSDOS__
/* MSDOS supports both the stock DOS shell and ports of Unixy shells.
{
/* Backslash-newline is handled differently depending on what
kind of string we're in: inside single-quoted strings you
- keep them; in double-quoted strings they disappear.
- For DOS/Windows/OS2, if we don't have a POSIX shell,
- we keep the pre-POSIX behavior of removing the
- backslash-newline. */
+ keep them; in double-quoted strings they disappear. For
+ DOS/Windows/OS2, if we don't have a POSIX shell, we keep the
+ pre-POSIX behavior of removing the backslash-newline. */
if (instring == '"'
#if defined (__MSDOS__) || defined (__EMX__) || defined (WINDOWS32)
|| !unixy_shell
char **
construct_command_argv (char *line, char **restp, struct file *file,
- int cmd_flags, char **batch_filename_ptr)
+ int cmd_flags, char **batch_filename_p)
{
char *shell, *ifs, *shellflags;
char **argv;
}
argv = construct_command_argv_internal (line, restp, shell, shellflags, ifs,
- cmd_flags, batch_filename_ptr);
+ cmd_flags, batch_filename_p);
free (shell);
free (shellflags);
# define CHAR_BIT 8
#endif
+#ifndef USHRT_MAX
+# define USHRT_MAX 65535
+#endif
+
/* Nonzero if the integer type T is signed. */
#define INTEGER_TYPE_SIGNED(t) ((t) -1 < 0)
if (backslash)
{
in = next_token (in);
- /* Removing this loop will fix Savannah bug #16670: do we want to? */
- while (out > line && isblank ((unsigned char)out[-1]))
- --out;
*out++ = ' ';
}
else
const char *pattern_percent, char *depstr,
unsigned int cmds_started, char *commands,
unsigned int commands_idx, int two_colon,
- const struct floc *flocp);
+ char prefix, const struct floc *flocp);
static void record_target_var (struct nameseq *filenames, char *defn,
enum variable_origin origin,
struct vmodifiers *vmod,
char *depstr = 0;
long nlines = 0;
int two_colon = 0;
+ char prefix;
const char *pattern = 0;
const char *pattern_percent;
struct floc *fstart;
fi.lineno = tgts_started; \
record_files (filenames, pattern, pattern_percent, depstr, \
cmds_started, commands, commands_idx, two_colon, \
- &fi); \
+ prefix, &fi); \
filenames = 0; \
} \
commands_idx = 0; \
linelen = strlen (line);
/* Check for a shell command line first.
- If it is not one, we can stop treating tab specially. */
+ If it is not one, we can stop treating cmd_prefix specially. */
if (line[0] == cmd_prefix)
{
if (no_targets)
/* Yep, this is a shell command, and we don't care. */
continue;
- /* Append this command line to the line being accumulated.
- Strip command prefix chars that appear after newlines. */
if (commands_idx == 0)
cmds_started = ebuf->floc.lineno;
+ /* Append this command line to the line being accumulated.
+ Skip the initial command prefix character. */
if (linelen + commands_idx > commands_len)
{
commands_len = (linelen + commands_idx) * 2;
commands = xrealloc (commands, commands_len);
}
- p = &commands[commands_idx];
- p2 = line + 1;
- while (--linelen)
- {
- ++commands_idx;
- *(p++) = *p2;
- if (p2[0] == '\n' && p2[1] == cmd_prefix)
- {
- ++p2;
- --linelen;
- }
- ++p2;
- }
- *p = '\n';
- ++commands_idx;
-
+ memcpy (&commands[commands_idx], line + 1, linelen - 1);
+ commands_idx += linelen - 1;
+ commands[commands_idx++] = '\n';
continue;
}
}
Unquote any = in the dependency list. */
find_char_unquote (lb_next, '=', 0, 0, 0);
+ /* Remember the command prefix for this target. */
+ prefix = cmd_prefix;
+
/* We have some targets, so don't ignore the following commands. */
no_targets = 0;
const char *pattern_percent, char *depstr,
unsigned int cmds_started, char *commands,
unsigned int commands_idx, int two_colon,
- const struct floc *flocp)
+ char prefix, const struct floc *flocp)
{
struct commands *cmds;
struct dep *deps;
cmds->fileinfo.lineno = cmds_started;
cmds->commands = xstrndup (commands, commands_idx);
cmds->command_lines = 0;
+ cmds->recipe_prefix = prefix;
}
else
cmds = 0;
anyway because somebody might want to free them later. */
r->cmds->commands = xstrdup (p->commands);
r->cmds->command_lines = 0;
+ r->cmds->recipe_prefix = RECIPEPREFIX_DEFAULT;
}
}
+2010-11-06 Paul Smith <psmith@gnu.org>
+
+ * scripts/features/targetvars: Fix known-good output for BS/NL changes.
+ * scripts/functions/call: Ditto.
+ * scripts/variables/special: Ditto.
+
+ * scripts/misc/bs-nl: New test suite for backslash/newline testing.
+
2010-08-29 Paul Smith <psmith@gnu.org>
* scripts/features/errors: Add new error message to output text.
# TEST #20: Check for continuation after semicolons
run_make_test(q!
-a: A = 'hello; \
+a: A = 'hello;\
world'
a: ; @echo $(A)
!,
DEP_foo = bar baz quux
DEP_baz = quux blarp
rest = $(wordlist 2,$(words ${1}),${1})
-tclose = $(if $1,$(firstword $1) \
+tclose = $(if $1,$(firstword $1)\
$(call tclose,$(sort ${DEP_$(firstword $1)} $(call rest,$1))))
all: ; @echo '$(call reverse,bar,foo)'; \
--- /dev/null
+# -*-perl-*-
+$description = "Test backslash-newline handling.";
+
+$details = "";
+
+# TEST #1
+# -------
+
+# Backslash-newlines in recipes
+
+# These are basic backslash-newlines with no tricks
+run_make_test("fast:;\@echo fa\\\nst\n",
+ '', 'fast');
+
+run_make_test("slow:;\@: no-op; echo sl\\\now\n",
+ '', 'slow');
+
+run_make_test("dquote:;\@echo \"dqu\\\note\"\n",
+ '', 'dquote');
+
+run_make_test("squote:;\@echo 'squ\\\note'\n",
+ '', "squ\\\note");
+
+# Ensure that a leading prefix character is omitted
+run_make_test("fast:;\@echo fa\\\n\tst\n",
+ '', 'fast');
+
+run_make_test("slow:;\@: no-op; echo sl\\\n\tow\n",
+ '', 'slow');
+
+run_make_test("dquote:;\@echo \"dqu\\\n\tote\"\n",
+ '', 'dquote');
+
+run_make_test("squote:;\@echo 'squ\\\n\tote'\n",
+ '', "squ\\\note");
+
+# Ensure that ONLY the leading prefix character is omitted
+run_make_test("fast:;\@echo fa\\\n\t st\n",
+ '', 'fa st');
+
+run_make_test("slow:;\@: no-op; echo sl\\\n\t\tow\n",
+ '', "sl ow");
+
+run_make_test("dquote:;\@echo \"dqu\\\n\t ote\"\n",
+ '', 'dqu ote');
+
+run_make_test("squote:;\@echo 'squ\\\n\t\t ote'\n",
+ '', "squ\\\n\t ote");
+
+# Backslash-newlines in variable values
+
+# Simple
+run_make_test("
+var = he\\\nllo
+var:;\@echo '|\$(var)|'",
+ '', "|he llo|");
+
+# Preserve preceding space
+run_make_test("
+var = he \\\nllo
+var:;\@echo '|\$(var)|'",
+ '', "|he llo|");
+
+# Remove leading space
+run_make_test("
+var = he\\\n llo
+var:;\@echo '|\$(var)|'",
+ '', "|he llo|");
+
+# One space per bs-nl
+run_make_test("
+var = he\\\n\\\n\\\n llo
+var:;\@echo '|\$(var)|'",
+ '', "|he llo|");
+
+1;
# Test the .RECIPEPREFIX variable
&run_make_test('
define foo
-: foo-one \
+: foo-one\
foo-two
: foo-three
: foo-four
switch (v->origin)
{
+ case o_automatic:
+ origin = _("automatic");
+ break;
case o_default:
origin = _("default");
break;
case o_override:
origin = _("`override' directive");
break;
- case o_automatic:
- origin = _("automatic");
- break;
case o_invalid:
default:
abort ();
}
+static void
+print_auto_variable (const void *item, void *arg)
+{
+ const struct variable *v = item;
+
+ if (v->origin == o_automatic)
+ print_variable (item, arg);
+}
+
+
+static void
+print_noauto_variable (const void *item, void *arg)
+{
+ const struct variable *v = item;
+
+ if (v->origin != o_automatic)
+ print_variable (item, arg);
+}
+
+
/* Print all the variables in SET. PREFIX is printed before
the actual variable definitions (everything else is comments). */
void
-print_variable_set (struct variable_set *set, char *prefix)
+print_variable_set (struct variable_set *set, char *prefix, int pauto)
{
- hash_map_arg (&set->table, print_variable, prefix);
+ hash_map_arg (&set->table, (pauto ? print_auto_variable : print_variable),
+ prefix);
fputs (_("# variable set hash-table stats:\n"), stdout);
fputs ("# ", stdout);
{
puts (_("\n# Variables\n"));
- print_variable_set (&global_variable_set, "");
+ print_variable_set (&global_variable_set, "", 0);
puts (_("\n# Pattern-specific Variable Values"));
print_file_variables (const struct file *file)
{
if (file->variables != 0)
- print_variable_set (file->variables->set, "# ");
+ print_variable_set (file->variables->set, "# ", 1);
+}
+
+void
+print_target_variables (const struct file *file)
+{
+ if (file->variables != 0)
+ {
+ int l = strlen (file->name);
+ char *t = alloca (l + 3);
+
+ strcpy (t, file->name);
+ t[l] = ':';
+ t[l+1] = ' ';
+ t[l+2] = '\0';
+
+ hash_map_arg (&file->variables->set->table, print_noauto_variable, t);
+ }
}
#ifdef WINDOWS32
void define_automatic_variables (void);
void initialize_file_variables (struct file *file, int reading);
void print_file_variables (const struct file *file);
-void print_variable_set (struct variable_set *set, char *prefix);
+void print_file_variables (const struct file *file);
+void print_target_variables (const struct file *file);
void merge_variable_set_lists (struct variable_set_list **to_list,
struct variable_set_list *from_list);
struct variable *do_variable_definition (const struct floc *flocp,