[PATCH] pass @-files to collect2 and beyond, take 2
Nathan Froyd
froydnj@codesourcery.com
Fri Apr 27 17:56:00 GMT 2007
On Tue, Apr 24, 2007 at 02:57:56PM -0400, DJ Delorie wrote:
> My only comment is that writeargv() should be passed a FILE*, not a
> file name, so that the application can do better error handling if the
> file cannot be opened. The proposed implementation has no way to tell
> what caused the call to fail, just that it failed. Also, the fclose()
> isn't checked for errors.
Revised patches attached:
1. writeargv takes a FILE*, not a char*. Error-checking for fopen and
fclose has been moved to the callers. f* calls in writeargv are
now all checked for errors.
2. HAVE_GNU_LD is now always defined, to 0/1 as appropriate.
Bootstrapped and tested on x86_64-unknown-linux-gnu, no regressions.
OK?
-Nathan
include/
2007-04-27 Nathan Froyd <froydnj@codesourcery.com>
* libiberty.h (writeargv): Declare.
libiberty/
2007-04-27 Nathan Froyd <froydnj@codesourcery.com>
* argv.c (writeargv): New function.
gcc/
2007-04-27 Nathan Froyd <froydnj@codesourcery.com>
* configure.ac: Add define for HAVE_GNU_LD.
* configure: Regenerate.
* config.in: Regenerate.
gcc/
2007-04-27 Nathan Froyd <froydnj@codesourcery.com>
* gcc.c (at_file_supplied): New variable.
(main): Set it if we expanded argv.
(do_spec_1): Pass an @-file to the linker if we were called with
an @-file argument and HAVE_GNU_LD.
* collect2.c (at_file_supplied): New variable.
(response_file): New variable.
(collect_exit): Unlink response_file if necessary.
(handler): Likewise.
(do_wait): Likewise.
(main): Set at_file_supplied if we expanded argv.
(collect_execute): Pass an @-file to subprocesses if we were called
with an @-file argument.
-------------- next part --------------
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c (revision 124103)
+++ gcc/gcc.c (working copy)
@@ -127,6 +127,9 @@ static const char dir_separator_str[] =
/* Flag set by cppspec.c to 1. */
int is_cpp_driver;
+/* Flag set to non-zero if an @file argument has been supplied to gcc. */
+static bool at_file_supplied;
+
/* Flag saying to pass the greatest exit code returned by a sub-process
to the calling program. */
static int pass_exit_codes;
@@ -5006,9 +5009,63 @@ do_spec_1 (const char *spec, int inswitc
int max = n_infiles;
max += lang_specific_extra_outfiles;
- for (i = 0; i < max; i++)
- if (outfiles[i])
- store_arg (outfiles[i], 0, 0);
+ if (HAVE_GNU_LD && at_file_supplied)
+ {
+ /* We are going to expand `%o' to `@FILE', where FILE
+ is a newly-created temporary filename. The filenames
+ that would usually be expanded in place of %o will be
+ written to the temporary file. */
+
+ char *temp_file = make_temp_file ("");
+ char *at_argument;
+ char **argv;
+ int n_files, j, status;
+ FILE *f;
+
+ at_argument = concat ("@", temp_file, NULL);
+ store_arg (at_argument, 0, 0);
+
+ /* Convert OUTFILES into a form suitable for writeargv. */
+
+ /* Determine how many are non-NULL. */
+ for (n_files = 0, i = 0; i < max; i++)
+ n_files += outfiles[i] != NULL;
+
+ argv = alloca (sizeof (char *) * (n_files + 1));
+
+ /* Copy the strings over. */
+ for (i = 0, j = 0; i < max; i++)
+ if (outfiles[i])
+ {
+ argv[j] = (char *) outfiles[i];
+ j++;
+ }
+ argv[j] = NULL;
+
+ f = fopen (temp_file, "w");
+
+ if (f == NULL)
+ fatal ("could not open temporary response file %s",
+ temp_file);
+
+ status = writeargv (argv, f);
+
+ if (status)
+ fatal ("could not write to temporary response file %s",
+ temp_file);
+
+ status = fclose (f);
+
+ if (EOF == status)
+ fatal ("could not close temporary response file %s",
+ temp_file);
+
+ record_temp_file (temp_file, 1, 1);
+ }
+ else
+ for (i = 0; i < max; i++)
+ if (outfiles[i])
+ store_arg (outfiles[i], 0, 0);
break;
}
@@ -6090,6 +6147,7 @@ main (int argc, char **argv)
char *specs_file;
const char *p;
struct user_specs *uptr;
+ char **old_argv = argv;
p = argv[0] + strlen (argv[0]);
while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
@@ -6100,6 +6158,10 @@ main (int argc, char **argv)
expandargv (&argc, &argv);
+ /* Determine if any expansions were made. */
+ if (argv != old_argv)
+ at_file_supplied = true;
+
prune_options (&argc, &argv);
#ifdef GCC_DRIVER_HOST_INITIALIZATION
Index: gcc/collect2.c
===================================================================
--- gcc/collect2.c (revision 124103)
+++ gcc/collect2.c (working copy)
@@ -1,7 +1,7 @@
/* Collect static initialization info into data structures that can be
traversed by C++ initialization and finalization routines.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
Contributed by Chris Smith (csmith@convex.com).
Heavily modified by Michael Meissner (meissner@cygnus.com),
Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
@@ -202,6 +202,9 @@ static struct head exports; /* list of
#endif
static struct head frame_tables; /* list of frame unwind info tables */
+static bool at_file_supplied; /* Whether to use @file arguments */
+static char *response_file; /* Name of any current response file */
+
struct obstack temporary_obstack;
char * temporary_firstobj;
@@ -302,6 +305,9 @@ collect_exit (int status)
if (status != 0 && output_file != 0 && output_file[0])
maybe_unlink (output_file);
+ if (response_file)
+ maybe_unlink (response_file);
+
exit (status);
}
@@ -393,6 +399,9 @@ handler (int signo)
maybe_unlink (export_file);
#endif
+ if (response_file)
+ maybe_unlink (response_file);
+
signal (signo, SIG_DFL);
raise (signo);
}
@@ -793,7 +802,15 @@ main (int argc, char **argv)
char **object_lst;
const char **object;
int first_file;
- int num_c_args = argc+9;
+ int num_c_args;
+ char **old_argv;
+
+ old_argv = argv;
+ expandargv (&argc, &argv);
+ if (argv != old_argv)
+ at_file_supplied = 1;
+
+ num_c_args = argc + 9;
no_demangle = !! getenv ("COLLECT_NO_DEMANGLE");
@@ -1513,6 +1530,12 @@ do_wait (const char *prog, struct pex_ob
error ("%s returned %d exit status", prog, ret);
collect_exit (ret);
}
+
+ if (response_file)
+ {
+ unlink (response_file);
+ response_file = NULL;
+ }
}
@@ -1525,6 +1548,47 @@ collect_execute (const char *prog, char
struct pex_obj *pex;
const char *errmsg;
int err;
+ char *response_arg = NULL;
+ char *response_argv[3] ATTRIBUTE_UNUSED;
+
+ if (HAVE_GNU_LD && at_file_supplied && argv[0] != NULL)
+ {
+ /* If using @file arguments, create a temporary file and put the
+ contents of argv into it. Then change argv to an array corresponding
+ to a single argument @FILE, where FILE is the temporary filename. */
+
+ char **current_argv = argv + 1;
+ char *argv0 = argv[0];
+ int status;
+ FILE *f;
+
+ /* Note: we assume argv contains at least one element; this is
+ checked above. */
+
+ response_file = make_temp_file ("");
+
+ f = fopen (response_file, "w");
+
+ if (f == NULL)
+ fatal ("could not open response file %s", response_file);
+
+ status = writeargv (current_argv, f);
+
+ if (status)
+ fatal ("could not write to response file %s", response_file);
+
+ status = fclose (f);
+
+ if (EOF == status)
+ fatal ("could not close response file %s", response_file);
+
+ response_arg = concat ("@", response_file, NULL);
+ response_argv[0] = argv0;
+ response_argv[1] = response_arg;
+ response_argv[2] = NULL;
+
+ argv = response_argv;
+ }
if (vflag || debug)
{
@@ -1568,6 +1632,9 @@ collect_execute (const char *prog, char
fatal (errmsg);
}
+ if (response_arg)
+ free (response_arg);
+
return pex;
}
-------------- next part --------------
Index: include/libiberty.h
===================================================================
--- include/libiberty.h (revision 124103)
+++ include/libiberty.h (working copy)
@@ -86,6 +86,10 @@ extern char **dupargv (char **) ATTRIBUT
extern void expandargv PARAMS ((int *, char ***));
+/* Write argv to an @-file, inserting necessary quoting. */
+
+extern int writeargv PARAMS ((char **, FILE *));
+
/* Return the last component of a path name. Note that we can't use a
prototype here because the parameter is declared inconsistently
across different systems, sometimes as "char *" and sometimes as
Index: libiberty/argv.c
===================================================================
--- libiberty/argv.c (revision 124103)
+++ libiberty/argv.c (working copy)
@@ -290,6 +290,62 @@ char **buildargv (const char *input)
/*
+@deftypefn Extension int writeargv (const char **@var{argv}, FILE *@{file})
+
+Write each member of ARGV, handling all necessary quoting, to the file
+named by FILE, separated by whitespace. Return 0 on success, non-zero
+if an error occurred while writing to FILE.
+
+@end deftypefn
+
+*/
+
+int
+writeargv (char **argv, FILE *f)
+{
+ int status = 0;
+
+ if (f == NULL)
+ return 1;
+
+ while (*argv != NULL)
+ {
+ int ret;
+ const char *arg = *argv;
+
+ while (*arg != EOS)
+ {
+ char c = *arg;
+
+ if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"')
+ if (EOF == fputc ('\\', f))
+ {
+ status = 1;
+ goto done;
+ }
+
+ if (EOF == fputc (c, f))
+ {
+ status = 1;
+ goto done;
+ }
+ arg++;
+ }
+
+ if (EOF == fputc ('\n', f))
+ {
+ status = 1;
+ goto done;
+ }
+ argv++;
+ }
+
+ done:
+ return status;
+}
+
+/*
+
@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
The @var{argcp} and @code{argvp} arguments are pointers to the usual
-------------- next part --------------
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac (revision 124103)
+++ gcc/configure.ac (working copy)
@@ -206,6 +206,9 @@ if test x"${DEFAULT_LINKER+set}" = x"set
[Define to enable the use of a default linker.])
fi
+gnu_ld=`if test x"$gnu_ld_flag" = x"yes"; then echo 1; else echo 0; fi`
+AC_DEFINE_UNQUOTED(HAVE_GNU_LD, $gnu_ld, [Define if using GNU ld.])
+
AC_MSG_CHECKING([whether a default linker was specified])
if test x"${DEFAULT_LINKER+set}" = x"set"; then
if test x"$gnu_ld_flag" = x"no"; then
More information about the Gcc-patches
mailing list