]> git.ipfire.org Git - thirdparty/make.git/commitdiff
Create a new function $(file ...)
authorPaul Smith <psmith@gnu.org>
Sun, 29 Jan 2012 18:12:22 +0000 (18:12 +0000)
committerPaul Smith <psmith@gnu.org>
Sun, 29 Jan 2012 18:12:22 +0000 (18:12 +0000)
ChangeLog
NEWS
build_w32.bat
configure.in
doc/make.texi
function.c
tests/ChangeLog
tests/scripts/functions/file [new file with mode: 0644]
tests/test_driver.pl

index 3c52a4a201c9f188e9cf787ba642b375f0882bc7..facb4cc40cbe4a8c291576c26246df6594615e6b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,13 @@
 2012-01-29  Paul Smith  <psmith@gnu.org>
 
+       * function.c (func_file): Create a new function, $(file ...)
+       * doc/make.texi (File Function): Document the $(file ..) function.
+       * NEWS: Announce it.
+
        * gmk-default.scm (to-string-maybe): Use a more portable way to
        test for unprintable characters.
        * configure.in [GUILE]: Guile 1.6 doesn't have pkg-config
+       * build_w32.bat: Ditto.
 
 2012-01-28  Eli Zaretskii  <eliz@gnu.org>
 
diff --git a/NEWS b/NEWS
index 4c50086dc7f94b8d2dbc748d01cdbd9baafedd67..20b8704918655c9e3a56f0199259f2fb86833fb8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,12 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
       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
+  makefile name and linenumber where it was defined are shown as well as the
+  prerequisites that caused the target to be considered out of date.
+
 * New feature: The "job server" capability is now supported on Windows.
   Implementation contributed by Troy Runkel <Troy.Runkel@mathworks.com>
 
@@ -32,16 +38,12 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
   interpreted as shell assignment.  Change your assignment to add whitespace
   between the "!" and "=": "variable! = value"
 
-* New Feature: GNU Guile integration
+* New feature: GNU Guile integration
   This version of GNU make can be compiled with GNU Guile integration.
   GNU Guile serves as an embedded extension language for make.
   See the "Guile Function" section in the GNU Make manual for details.
 
-* 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
-  makefile name and linenumber where it was defined are shown as well as the
-  prerequisites that caused the target to be considered out of date.
+* New function: $(file ...) writes to a file.
 
 * On failure, the makefile name and linenumber of the recipe that failed are
   shown.
index 57aa037961aed159770b00d4b9953d987283d84b..6fbc67acaf5c9da491c05b86f7401702429187d4 100644 (file)
@@ -47,12 +47,6 @@ if not ERRORLEVEL 1 set /P GUILECFLAGS= < guile.tmp
 pkg-config --libs --static --short-errors %PKGMSC% "guile-1.8" > guile.tmp\r
 if not ERRORLEVEL 1 set /P GUILELIBS= < guile.tmp\r
 if not "%GUILECFLAGS%" == "" GoTo GuileDone\r
-echo "Checking for Guile 1.6"\r
-pkg-config --cflags --short-errors "guile-1.6" > guile.tmp\r
-if not ERRORLEVEL 1 set /P GUILECFLAGS= < guile.tmp\r
-pkg-config --libs --static --short-errors %PKGMSC% "guile-2.0" > guile.tmp\r
-if not ERRORLEVEL 1 set /P GUILELIBS= < guile.tmp\r
-if not "%GUILECFLAGS%" == "" GoTo GuileDone\r
 echo "No Guile found, building without Guile"\r
 GoTo NoGuile\r
 :NoPkgCfg\r
index a2050c7a58888054fb45a91c1fba2c874789833a..90b55ea8b66d838e6b45acd322cc6ef202a0c106 100644 (file)
@@ -180,8 +180,7 @@ AC_ARG_WITH([guile], [AS_HELP_STRING([--with-guile],
 AS_IF([test "x$with_guile" != xno],
 [ PKG_CHECK_MODULES([GUILE], [guile-2.0], [have_guile=yes],
   [PKG_CHECK_MODULES([GUILE], [guile-1.8], [have_guile=yes],
-   [PKG_CHECK_MODULES([GUILE], [guile-1.6], [have_guile=yes],
-    [have_guile=no])])])
+    [have_guile=no])])
 ])
 
 AS_IF([test "$have_guile" = yes],
index 63390c8cc4d0477466bee44c34d633b379228396..9b8faee67552e616714ff0be44a2becc8acf9729 100644 (file)
@@ -265,6 +265,7 @@ Functions for Transforming Text
 * File Name Functions::         Functions for manipulating file names.
 * Conditional Functions::       Functions that implement conditions.
 * Foreach Function::            Repeat some text with controlled variation.
+* File Function::               Write text to a file.
 * Call Function::               Expand a user-defined function.
 * Value Function::              Return the un-expanded value of a variable.
 * Eval Function::               Evaluate the arguments as makefile syntax.
@@ -6563,6 +6564,7 @@ be substituted.
 * File Name Functions::         Functions for manipulating file names.
 * Conditional Functions::       Functions that implement conditions.
 * Foreach Function::            Repeat some text with controlled variation.
+* File Function::               Write text to a file.
 * Call Function::               Expand a user-defined function.
 * Value Function::              Return the un-expanded value of a variable.
 * Eval Function::               Evaluate the arguments as makefile syntax.
@@ -7214,7 +7216,7 @@ the result of the expansion is the expansion of the last argument.
 
 @end table
 
-@node Foreach Function, Call Function, Conditional Functions, Functions
+@node Foreach Function, File Function, Conditional Functions, Functions
 @section The @code{foreach} Function
 @findex foreach
 @cindex words, iterating over
@@ -7302,7 +7304,69 @@ might be useful if the value of @code{find_files} references the variable
 whose name is @samp{Esta-escrito-en-espanol!} (es un nombre bastante largo,
 no?), but it is more likely to be a mistake.
 
-@node Call Function, Value Function, Foreach Function, Functions
+@node File Function, Call Function, Foreach Function, Functions
+@section The @code{file} Function
+@findex file
+@cindex writing to a file
+@cindex file, writing to
+
+The @code{file} function allows the makefile to write to a file.  Two
+modes of writing are supported: overwrite, where the text is written
+to the beginning of the file and any existing content is lost, and
+append, where the text is written to the end of the file, preserving
+the existing content.  In all cases the file is created if it does not
+exist.
+
+The syntax of the @code{file} function is:
+
+@example
+$(file @var{op} @var{filename},@var{text})
+@end example
+
+The operator @var{op} can be either @code{>} which indicates overwrite
+mode, or @code{>>} which indicates append mode.  The @var{filename}
+indicates the file to be written to.  There may optionally be
+whitespace between the operator and the file name.
+
+When the @code{file} function is expanded all its arguments are
+expanded first, then the file indicated by @var{filename} will be
+opened in the mode described by @var{op}.  Finally @var{text} will be
+written to the file.  If @var{text} does not already end in a newline,
+a final newline will be written.  The result of evaluating the
+@code{file} function is always the empty string.
+
+It is a fatal error if the file cannot be opened for writing, or if
+the write operation fails.
+
+For example, the @code{file} function can be useful if your build
+system has a limited command line size and your recipe runs a command
+that can accept arguments from a file as well.  Many commands use the
+convention that an argument prefixed with an @code{@@} specifies a
+file containing more arguments.  Then you might write your recipe in
+this way:
+
+@example
+@group
+program: $(OBJECTS)
+        $(file >$@@.in,$^)
+        $(CMD) $(CMDFLAGS) @@$@@.in
+        @@rm $@@.in
+@end group
+@end example
+
+If the command required each argument to be on a separate line of the
+input file, you might write your recipe like this:
+
+@example
+@group
+program: $(OBJECTS)
+        $(file >$@@.in,) $(foreach O,$^,$(file >>$@@.in,$O))
+        $(CMD) $(CMDFLAGS) @@$@@.in
+        @@rm $@@.in
+@end group
+@end example
+
+@node Call Function, Value Function, File Function, Functions
 @section The @code{call} Function
 @findex call
 @cindex functions, user defined
index 29b106fc04048b859c94b00615c99ef7e699bddc..5acbb761cc7505d39c01d32373a83bbccfd889a6 100644 (file)
@@ -2104,6 +2104,45 @@ func_realpath (char *o, char **argv, const char *funcname UNUSED)
   return o;
 }
 
+static char *
+func_file (char *o, char **argv, const char *funcname UNUSED)
+{
+  char *fn = argv[0];
+
+  if (fn[0] == '>')
+    {
+      FILE *fp;
+      const char *mode = "w";
+
+      /* We are writing a file.  */
+      ++fn;
+      if (fn[0] == '>')
+        {
+          mode = "a";
+          ++fn;
+        }
+      fn = next_token (fn);
+
+      fp = fopen (fn, mode);
+      if (fp == NULL)
+        fatal (reading_file, _("open: %s: %s"), fn, strerror (errno));
+      else
+        {
+          int l = strlen (argv[1]);
+          int nl = (l == 0 || argv[1][l-1] != '\n');
+
+          if (fputs (argv[1], fp) == EOF || (nl && fputc('\n', fp) == EOF))
+            fatal (reading_file, _("write: %s: %s"), fn, strerror (errno));
+
+          fclose (fp);
+        }
+    }
+  else
+    fatal (reading_file, _("Invalid file operation: %s"), fn);
+
+  return o;
+}
+
 static char *
 func_abspath (char *o, char **argv, const char *funcname UNUSED)
 {
@@ -2191,6 +2230,7 @@ static struct function_table_entry function_table_init[] =
   { STRING_SIZE_TUPLE("and"),           1,  0,  0,  func_and},
   { STRING_SIZE_TUPLE("value"),         0,  1,  1,  func_value},
   { STRING_SIZE_TUPLE("eval"),          0,  1,  1,  func_eval},
+  { STRING_SIZE_TUPLE("file"),          1,  2,  1,  func_file},
 #ifdef EXPERIMENTAL
   { STRING_SIZE_TUPLE("eq"),            2,  2,  1,  func_eq},
   { STRING_SIZE_TUPLE("not"),           0,  1,  1,  func_not},
index f603fc8267f886f9453f352503a69b0dec33a6ff..3e0643cdb7deec400db9e922640e559c1d598fa4 100644 (file)
@@ -1,3 +1,7 @@
+2012-01-29  Paul Smith  <psmith@gnu.org>
+
+       * scripts/functions/file: Test the new $(file ...) function.
+
 2012-01-12  Paul Smith  <psmith@gnu.org>
 
        * scripts/functions/guile: New regression tests for Guile support.
diff --git a/tests/scripts/functions/file b/tests/scripts/functions/file
new file mode 100644 (file)
index 0000000..b994af8
--- /dev/null
@@ -0,0 +1,94 @@
+#                                                                    -*-perl-*-
+
+$description = 'Test the $(file ...) function.';
+
+# Test > and >>
+run_make_test(q!
+define A
+a
+b
+endef
+B = c d
+$(file >file.out,$(A))
+$(foreach L,$(B),$(file >>     file.out,$L))
+x:;@echo hi; cat file.out
+!,
+              '', "hi\na\nb\nc\nd");
+
+unlink('file.out');
+
+# Test >> to a non-existent file
+run_make_test(q!
+define A
+a
+b
+endef
+$(file     >>     file.out,$(A))
+x:;@cat file.out
+!,
+              '', "a\nb");
+
+unlink('file.out');
+
+# Test > to a read-only file
+touch('file.out');
+chmod(0444, 'file.out');
+
+# Find the error that will be printed
+my $e;
+open(my $F, '>', 'file.out') and die "Opened read-only file!\n";
+$e = "$!";
+
+run_make_test(q!
+define A
+a
+b
+endef
+$(file     >     file.out,$(A))
+x:;@cat file.out
+!,
+              '', "#MAKEFILE#:6: *** open: file.out: $e.  Stop.",
+              512);
+
+unlink('file.out');
+
+# Use variables for operator and filename
+run_make_test(q!
+define A
+a
+b
+endef
+OP = >
+FN = file.out
+$(file     $(OP)     $(FN),$(A))
+x:;@cat file.out
+!,
+              '', "a\nb");
+
+unlink('file.out');
+
+# Don't add newlines if one already exists
+run_make_test(q!
+define A
+a
+b
+
+endef
+$(file >file.out,$(A))
+x:;@cat file.out
+!,
+              '', "a\nb");
+
+unlink('file.out');
+
+# Empty text
+run_make_test(q!
+$(file >file.out,)
+$(file >>file.out,)
+x:;@cat file.out
+!,
+              '', "\n\n");
+
+unlink('file.out');
+
+1;
index b57d936424fa7aab2c1057aaf1f2676dfbb931fa..4ec3a1199c3307b9e5f31287af7efe9b9d101ca8 100644 (file)
@@ -89,6 +89,7 @@ sub toplevel
 
   foreach (# UNIX-specific things
            'TZ', 'TMPDIR', 'HOME', 'USER', 'LOGNAME', 'PATH',
+           'LD_LIBRARY_PATH',
            # Purify things
            'PURIFYOPTIONS',
            # Windows NT-specific stuff