From 2091ff6689ae73c4b95338a435d1c6e7b743599e Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 8 May 2007 00:37:39 +0000 Subject: [PATCH] libiberty.h (writeargv): Declare. include/ 2007-05-07 Nathan Froyd * libiberty.h (writeargv): Declare. libiberty/ 2007-05-07 Nathan Froyd * argv.c (writeargv): New function. gcc/ 2007-05-07 Nathan Froyd * 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. * configure.ac: Add define for HAVE_GNU_LD. * configure: Regenerate. * config.in: Regenerate. From-SVN: r124532 --- gcc/ChangeLog | 20 ++++++++++++- gcc/collect2.c | 71 +++++++++++++++++++++++++++++++++++++++++++-- gcc/config.in | 6 ++++ gcc/configure | 9 +++++- gcc/configure.ac | 3 ++ gcc/gcc.c | 68 +++++++++++++++++++++++++++++++++++++++++-- include/ChangeLog | 4 +++ include/libiberty.h | 4 +++ libiberty/ChangeLog | 4 +++ libiberty/argv.c | 56 +++++++++++++++++++++++++++++++++++ 10 files changed, 238 insertions(+), 7 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a7df7b0eecb..c57813d4031 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2007-05-07 Nathan Froyd + + * 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. + * configure.ac: Add define for HAVE_GNU_LD. + * configure: Regenerate. + * config.in: Regenerate. + 2007-05-07 Naveen.H.S * config/m32c/muldiv.md (mulhisi3_c): Limit the mode of the 2nd @@ -28,7 +46,7 @@ ashrpsi3, lshrpsi3): Update shift count constraint. 2007-05-07 Danny Smith - Nathan Froyd PR 22133 * c-incpath.c (add_path): Strip trailing path separators. diff --git a/gcc/collect2.c b/gcc/collect2.c index c6c1f3f4a2c..1ef174f534e 100644 --- a/gcc/collect2.c +++ b/gcc/collect2.c @@ -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 exported symbols */ #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_obj *pex) 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 **argv, const char *outname, 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 **argv, const char *outname, fatal (errmsg); } + if (response_arg) + free (response_arg); + return pex; } diff --git a/gcc/config.in b/gcc/config.in index 7e60a3ef347..7864d8c066f 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -869,6 +869,12 @@ #endif +/* Define if using GNU ld. */ +#ifndef USED_FOR_TARGET +#undef HAVE_GNU_LD +#endif + + /* Define if you have the iconv() function. */ #ifndef USED_FOR_TARGET #undef HAVE_ICONV diff --git a/gcc/configure b/gcc/configure index 17e4fdc7663..b3aa2b09ce7 100755 --- a/gcc/configure +++ b/gcc/configure @@ -1767,6 +1767,13 @@ _ACEOF fi +gnu_ld=`if test x"$gnu_ld_flag" = x"yes"; then echo 1; else echo 0; fi` + +cat >>confdefs.h <<_ACEOF +#define HAVE_GNU_LD $gnu_ld +_ACEOF + + echo "$as_me:$LINENO: checking whether a default linker was specified" >&5 echo $ECHO_N "checking whether a default linker was specified... $ECHO_C" >&6 if test x"${DEFAULT_LINKER+set}" = x"set"; then @@ -7665,7 +7672,7 @@ if test "${gcc_cv_prog_makeinfo_modern+set}" = set; then else ac_prog_version=`$MAKEINFO --version 2>&1 | sed -n 's/^.*GNU texinfo.* \([0-9][0-9.]*\).*$/\1/p'` - echo "configure:7668: version of makeinfo is $ac_prog_version" >&5 + echo "configure:7675: version of makeinfo is $ac_prog_version" >&5 case $ac_prog_version in '') gcc_cv_prog_makeinfo_modern=no;; 4.[4-9]*) diff --git a/gcc/configure.ac b/gcc/configure.ac index 9a7c563ec7b..708ce1681a3 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -206,6 +206,9 @@ if test x"${DEFAULT_LINKER+set}" = x"set"; then [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 diff --git a/gcc/gcc.c b/gcc/gcc.c index 10468026939..5ed41bd66ff 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -127,6 +127,9 @@ static const char dir_separator_str[] = { DIR_SEPARATOR, 0 }; /* 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; @@ -5009,9 +5012,63 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) 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, !save_temps_flag, !save_temps_flag); + } + else + for (i = 0; i < max; i++) + if (outfiles[i]) + store_arg (outfiles[i], 0, 0); break; } @@ -6093,6 +6150,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])) @@ -6103,6 +6161,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 diff --git a/include/ChangeLog b/include/ChangeLog index 5fcce7210bf..b4112bfc7be 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2007-05-07 Nathan Froyd + + * libiberty.h (writeargv): Declare. + 2007-04-25 Mark Mitchell * demangle.h: Change license to LGPL + exception. diff --git a/include/libiberty.h b/include/libiberty.h index 7a58b711c37..4e697343fb6 100644 --- a/include/libiberty.h +++ b/include/libiberty.h @@ -86,6 +86,10 @@ extern char **dupargv (char **) ATTRIBUTE_MALLOC; 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 diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index c4e70721036..a4217845c73 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,7 @@ +2007-05-07 Nathan Froyd + + * argv.c (writeargv): New function. + 2007-05-05 Geoffrey Keating * cp-demangle.c (d_name): Detect local-source-name. diff --git a/libiberty/argv.c b/libiberty/argv.c index e76c1f825d2..a04f50d7f49 100644 --- a/libiberty/argv.c +++ b/libiberty/argv.c @@ -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