X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftlink.c;h=b2111dcf4d5f0b3e885001e6be0db57d1eab149c;hb=b0d8e49cb34af0a14e5e21c23a7933d482c5d3ec;hp=7219cd17f12108cb70909d1d1ef7ec7556f1d66e;hpb=05ad12788a6c4d5a8737cf454225aef9eb32afb6;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tlink.c b/gcc/tlink.c index 7219cd17f12..b2111dcf4d5 100644 --- a/gcc/tlink.c +++ b/gcc/tlink.c @@ -1,46 +1,33 @@ /* Scan linker error messages for missing template instantiations and provide them. - Copyright (C) 1995, 1998 Free Software Foundation, Inc. + Copyright (C) 1995, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. Contributed by Jason Merrill (jason@cygnus.com). -This file is part of GNU CC. +This file is part of GCC. -GNU CC 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 2, or (at your option) -any later version. +GCC 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 2, or (at your option) any later +version. -GNU CC 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. +GCC 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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ -#include -#include #include "config.h" -#include "hash.h" +#include "system.h" +#include "intl.h" +#include "obstack.h" +#include "hashtab.h" #include "demangle.h" - -#ifdef HAVE_STDLIB_H -#include -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_STRING_H -#include -#else -#ifdef HAVE_STRINGS_H -#include -#endif -#endif +#include "collect2.h" #define MAX_ITERATIONS 17 @@ -48,28 +35,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free -extern char * xmalloc PARAMS((unsigned)); -extern void free (); -extern char * getenv (); - -/* Defined in collect2.c. */ -extern int vflag, debug; -extern char *ldout; -extern char *c_file_name; -extern struct obstack temporary_obstack; -extern struct obstack permanent_obstack; -extern char * temporary_firstobj; - /* Defined in the automatically-generated underscore.c. */ extern int prepends_underscore; static int tlink_verbose; -/* Hash table code. */ +/* Hash table boilerplate for working with htab_t. We have hash tables + for symbol names, file names, and demangled symbols. */ typedef struct symbol_hash_entry { - struct hash_entry root; + const char *key; struct file_hash_entry *file; int chosen; int tweaking; @@ -78,7 +54,7 @@ typedef struct symbol_hash_entry typedef struct file_hash_entry { - struct hash_entry root; + const char *key; const char *args; const char *dir; const char *main; @@ -87,106 +63,123 @@ typedef struct file_hash_entry typedef struct demangled_hash_entry { - struct hash_entry root; + const char *key; const char *mangled; } demangled; -static struct hash_table symbol_table; +/* Hash and comparison functions for these hash tables. */ -static struct hash_entry * -symbol_hash_newfunc (entry, table, string) - struct hash_entry *entry; - struct hash_table *table; - const char *string; +static int hash_string_eq PARAMS ((const void *, const void *)); +static hashval_t hash_string_hash PARAMS ((const void *)); + +static int +hash_string_eq (s1_p, s2_p) + const void *s1_p; + const void *s2_p; { - struct symbol_hash_entry *ret = (struct symbol_hash_entry *) entry; - if (ret == NULL) - { - ret = ((struct symbol_hash_entry *) - hash_allocate (table, sizeof (struct symbol_hash_entry))); - if (ret == NULL) - return NULL; - } - ret = ((struct symbol_hash_entry *) - hash_newfunc ((struct hash_entry *) ret, table, string)); - ret->file = NULL; - ret->chosen = 0; - ret->tweaking = 0; - ret->tweaked = 0; - return (struct hash_entry *) ret; + const char *const *s1 = (const char *const *)s1_p; + const char *s2 = (const char *)s2_p; + return strcmp (*s1, s2) == 0; } -static struct symbol_hash_entry * -symbol_hash_lookup (string, create) - const char *string; - boolean create; +static hashval_t +hash_string_hash (s_p) + const void *s_p; { - return ((struct symbol_hash_entry *) - hash_lookup (&symbol_table, string, create, true)); + const char *const *s = (const char *const *)s_p; + return (*htab_hash_string) (*s); } -static struct hash_table file_table; +static htab_t symbol_table; + +static struct symbol_hash_entry * symbol_hash_lookup PARAMS ((const char *, + int)); +static struct file_hash_entry * file_hash_lookup PARAMS ((const char *)); +static struct demangled_hash_entry * + demangled_hash_lookup PARAMS ((const char *, int)); +static void symbol_push PARAMS ((symbol *)); +static symbol * symbol_pop PARAMS ((void)); +static void file_push PARAMS ((file *)); +static file * file_pop PARAMS ((void)); +static void tlink_init PARAMS ((void)); +static int tlink_execute PARAMS ((const char *, char **, const char *)); +static char * frob_extension PARAMS ((const char *, const char *)); +static char * obstack_fgets PARAMS ((FILE *, struct obstack *)); +static char * tfgets PARAMS ((FILE *)); +static char * pfgets PARAMS ((FILE *)); +static void freadsym PARAMS ((FILE *, file *, int)); +static void read_repo_file PARAMS ((file *)); +static void maybe_tweak PARAMS ((char *, file *)); +static int recompile_files PARAMS ((void)); +static int read_repo_files PARAMS ((char **)); +static void demangle_new_symbols PARAMS ((void)); +static int scan_linker_output PARAMS ((const char *)); + +/* Look up an entry in the symbol hash table. */ -static struct hash_entry * -file_hash_newfunc (entry, table, string) - struct hash_entry *entry; - struct hash_table *table; +static struct symbol_hash_entry * +symbol_hash_lookup (string, create) const char *string; + int create; { - struct file_hash_entry *ret = (struct file_hash_entry *) entry; - if (ret == NULL) + PTR *e; + e = htab_find_slot_with_hash (symbol_table, string, + (*htab_hash_string)(string), + create ? INSERT : NO_INSERT); + if (e == NULL) + return NULL; + if (*e == NULL) { - ret = ((struct file_hash_entry *) - hash_allocate (table, sizeof (struct file_hash_entry))); - if (ret == NULL) - return NULL; + struct symbol_hash_entry *v; + *e = v = xcalloc (1, sizeof (*v)); + v->key = xstrdup (string); } - ret = ((struct file_hash_entry *) - hash_newfunc ((struct hash_entry *) ret, table, string)); - ret->args = NULL; - ret->dir = NULL; - ret->main = NULL; - ret->tweaking = 0; - return (struct hash_entry *) ret; + return *e; } -static struct file_hash_entry * -file_hash_lookup (string) - const char *string; -{ - return ((struct file_hash_entry *) - hash_lookup (&file_table, string, true, true)); -} +static htab_t file_table; -static struct hash_table demangled_table; +/* Look up an entry in the file hash table. */ -static struct hash_entry * -demangled_hash_newfunc (entry, table, string) - struct hash_entry *entry; - struct hash_table *table; +static struct file_hash_entry * +file_hash_lookup (string) const char *string; { - struct demangled_hash_entry *ret = (struct demangled_hash_entry *) entry; - if (ret == NULL) + PTR *e; + e = htab_find_slot_with_hash (file_table, string, + (*htab_hash_string)(string), + INSERT); + if (*e == NULL) { - ret = ((struct demangled_hash_entry *) - hash_allocate (table, sizeof (struct demangled_hash_entry))); - if (ret == NULL) - return NULL; + struct file_hash_entry *v; + *e = v = xcalloc (1, sizeof (*v)); + v->key = xstrdup (string); } - ret = ((struct demangled_hash_entry *) - hash_newfunc ((struct hash_entry *) ret, table, string)); - ret->mangled = NULL; - return (struct hash_entry *) ret; + return *e; } +static htab_t demangled_table; + +/* Look up an entry in the demangled name hash table. */ + static struct demangled_hash_entry * demangled_hash_lookup (string, create) const char *string; - boolean create; + int create; { - return ((struct demangled_hash_entry *) - hash_lookup (&demangled_table, string, create, true)); + PTR *e; + e = htab_find_slot_with_hash (demangled_table, string, + (*htab_hash_string)(string), + create ? INSERT : NO_INSERT); + if (e == NULL) + return NULL; + if (*e == NULL) + { + struct demangled_hash_entry *v; + *e = v = xcalloc (1, sizeof (*v)); + v->key = xstrdup (string); + } + return *e; } /* Stack code. */ @@ -264,14 +257,20 @@ file_pop () /* Other machinery. */ +/* Initialize the tlink machinery. Called from do_tlink. */ + static void tlink_init () { - char *p; - - hash_table_init (&symbol_table, symbol_hash_newfunc); - hash_table_init (&file_table, file_hash_newfunc); - hash_table_init (&demangled_table, demangled_hash_newfunc); + const char *p; + + symbol_table = htab_create (500, hash_string_hash, hash_string_eq, + NULL); + file_table = htab_create (500, hash_string_hash, hash_string_eq, + NULL); + demangled_table = htab_create (500, hash_string_hash, hash_string_eq, + NULL); + obstack_begin (&symbol_stack_obstack, 0); obstack_begin (&file_stack_obstack, 0); @@ -290,22 +289,23 @@ tlink_init () static int tlink_execute (prog, argv, redir) - char *prog; + const char *prog; char **argv; - char *redir; + const char *redir; { collect_execute (prog, argv, redir); return collect_wait (prog); -} +} static char * frob_extension (s, ext) - char *s, *ext; + const char *s; + const char *ext; { - char *p = (char *) rindex (s, '/'); + const char *p = strrchr (s, '/'); if (! p) p = s; - p = (char *) rindex (p, '.'); + p = strrchr (p, '.'); if (! p) p = s + strlen (s); @@ -343,6 +343,12 @@ pfgets (stream) /* Real tlink code. */ +/* Subroutine of read_repo_file. We are reading the repo file for file F, + which is coming in on STREAM, and the symbol that comes next in STREAM + is offerred, chosen or provided if CHOSEN is 0, 1 or 2, respectively. + + XXX "provided" is unimplemented, both here and in the compiler. */ + static void freadsym (stream, f, chosen) FILE *stream; @@ -352,18 +358,22 @@ freadsym (stream, f, chosen) symbol *sym; { - char *name = tfgets (stream); + const char *name = tfgets (stream); sym = symbol_hash_lookup (name, true); } if (sym->file == NULL) { + /* We didn't have this symbol already, so we choose this file. */ + symbol_push (sym); sym->file = f; sym->chosen = chosen; } else if (chosen) { + /* We want this file; cast aside any pretender. */ + if (sym->chosen && sym->file != f) { if (sym->chosen == 1) @@ -380,15 +390,17 @@ freadsym (stream, f, chosen) } } +/* Read in the repo file denoted by F, and record all its information. */ + static void read_repo_file (f) file *f; { char c; - FILE *stream = fopen (f->root.string, "r"); + FILE *stream = fopen (f->key, "r"); if (tlink_verbose >= 2) - fprintf (stderr, "collect: reading %s\n", f->root.string); + fprintf (stderr, _("collect: reading %s\n"), f->key); while (fscanf (stream, "%c ", &c) == 1) { @@ -422,6 +434,11 @@ read_repo_file (f) f->dir = "."; } +/* We might want to modify LINE, which is a symbol line from file F. We do + this if either we saw an error message referring to the symbol in + question, or we have already allocated the symbol to another file and + this one wants to emit it as well. */ + static void maybe_tweak (line, f) char *line; @@ -442,16 +459,24 @@ maybe_tweak (line, f) } } +/* Update the repo files for each of the object files we have adjusted and + recompile. + + XXX Should this use collect_execute instead of system? */ + static int recompile_files () { file *f; + putenv (xstrdup ("COMPILER_PATH")); + putenv (xstrdup ("LIBRARY_PATH")); + while ((f = file_pop ()) != NULL) { char *line, *command; - FILE *stream = fopen (f->root.string, "r"); - char *outname = frob_extension (f->root.string, ".rnw"); + FILE *stream = fopen (f->key, "r"); + const char *const outname = frob_extension (f->key, ".rnw"); FILE *output = fopen (outname, "w"); while ((line = tfgets (stream)) != NULL) @@ -466,7 +491,7 @@ recompile_files () } fclose (stream); fclose (output); - rename (outname, f->root.string); + rename (outname, f->key); obstack_grow (&temporary_obstack, "cd ", 3); obstack_grow (&temporary_obstack, f->dir, strlen (f->dir)); @@ -478,7 +503,7 @@ recompile_files () command = obstack_copy0 (&temporary_obstack, f->main, strlen (f->main)); if (tlink_verbose) - fprintf (stderr, "collect: recompiling %s\n", f->main); + fprintf (stderr, _("collect: recompiling %s\n"), f->main); if (tlink_verbose >= 3) fprintf (stderr, "%s\n", command); @@ -492,6 +517,9 @@ recompile_files () return 1; } +/* The first phase of processing: determine which object files have + .rpo files associated with them, and read in the information. */ + static int read_repo_files (object_lst) char **object_lst; @@ -500,9 +528,15 @@ read_repo_files (object_lst) for (; *object; object++) { - char *p = frob_extension (*object, ".rpo"); + const char *p; file *f; + /* Don't bother trying for ld flags. */ + if (*object[0] == '-') + continue; + + p = frob_extension (*object, ".rpo"); + if (! file_exists (p)) continue; @@ -517,6 +551,8 @@ read_repo_files (object_lst) return (symbol_stack != NULL); } +/* Add the demangled forms of any new symbols to the hash table. */ + static void demangle_new_symbols () { @@ -525,19 +561,22 @@ demangle_new_symbols () while ((sym = symbol_pop ()) != NULL) { demangled *dem; - char *p = cplus_demangle (sym->root.string, DMGL_PARAMS | DMGL_ANSI); + const char *p = cplus_demangle (sym->key, DMGL_PARAMS | DMGL_ANSI); if (! p) continue; dem = demangled_hash_lookup (p, true); - dem->mangled = sym->root.string; + dem->mangled = sym->key; } } +/* Step through the output of the linker, in the file named FNAME, and + adjust the settings for each symbol encountered. */ + static int scan_linker_output (fname) - char *fname; + const char *fname; { FILE *stream = fopen (fname, "r"); char *line; @@ -547,14 +586,14 @@ scan_linker_output (fname) char *p = line, *q; symbol *sym; int end; - - while (*p && isspace (*p)) + + while (*p && ISSPACE ((unsigned char)*p)) ++p; if (! *p) continue; - for (q = p; *q && ! isspace (*q); ++q) + for (q = p; *q && ! ISSPACE ((unsigned char)*q); ++q) ; /* Try the first word on the line. */ @@ -567,27 +606,58 @@ scan_linker_output (fname) *q = 0; sym = symbol_hash_lookup (p, false); + /* Some SVR4 linkers produce messages like + ld: 0711-317 ERROR: Undefined symbol: .g__t3foo1Zi + */ + if (! sym && ! end && strstr (q+1, "Undefined symbol: ")) + { + char *p = strrchr (q+1, ' '); + p++; + if (*p == '.') + p++; + if (*p == '_' && prepends_underscore) + p++; + sym = symbol_hash_lookup (p, false); + } + if (! sym && ! end) - /* Try a mangled name in `quotes'. */ + /* Try a mangled name in quotes. */ { + const char *oldq = q+1; demangled *dem = 0; - p = (char *) index (q+1, '`'); q = 0; -#define MUL "multiple definition of " -#define UND "undefined reference to " - - if (p && (p - line > sizeof (MUL))) + /* First try `GNU style'. */ + p = strchr (oldq, '`'); + if (p) + p++, q = strchr (p, '\''); + /* Then try "double quotes". */ + else if (p = strchr (oldq, '"'), p) + p++, q = strchr (p, '"'); + + /* Don't let the strstr's below see the demangled name; we + might get spurious matches. */ + if (p) + p[-1] = '\0'; + + /* We need to check for certain error keywords here, or we would + mistakenly use GNU ld's "In function `foo':" message. */ + if (q && (strstr (oldq, "ndefined") + || strstr (oldq, "nresolved") + || strstr (oldq, "nsatisfied") + || strstr (oldq, "ultiple"))) { - char *beg = p - sizeof (MUL) + 1; - *p = 0; - if (!strcmp (beg, MUL) || !strcmp (beg, UND)) - p++, q = (char *) index (p, '\''); + *q = 0; + dem = demangled_hash_lookup (p, false); + if (dem) + sym = symbol_hash_lookup (dem->mangled, false); + else + { + if (*p == '_' && prepends_underscore) + ++p; + sym = symbol_hash_lookup (p, false); + } } - if (q) - *q = 0, dem = demangled_hash_lookup (p, false); - if (dem) - sym = symbol_hash_lookup (dem->mangled, false); } if (sym && sym->tweaked) @@ -598,12 +668,12 @@ scan_linker_output (fname) if (sym && !sym->tweaking) { if (tlink_verbose >= 2) - fprintf (stderr, "collect: tweaking %s in %s\n", - sym->root.string, sym->file->root.string); + fprintf (stderr, _("collect: tweaking %s in %s\n"), + sym->key, sym->file->key); sym->tweaking = 1; file_push (sym->file); } - + obstack_free (&temporary_obstack, temporary_firstobj); } @@ -611,9 +681,18 @@ scan_linker_output (fname) return (file_stack != NULL); } +/* Entry point for tlink. Called from main in collect2.c. + + Iteratively try to provide definitions for all the unresolved symbols + mentioned in the linker error messages. + + LD_ARGV is an array of arguments for the linker. + OBJECT_LST is an array of object files that we may be able to recompile + to provide missing definitions. Currently ignored. */ + void do_tlink (ld_argv, object_lst) - char **ld_argv, **object_lst; + char **ld_argv, **object_lst ATTRIBUTE_UNUSED; { int exit = tlink_execute ("ld", ld_argv, ldout); @@ -636,7 +715,7 @@ do_tlink (ld_argv, object_lst) if (! recompile_files ()) break; if (tlink_verbose) - fprintf (stderr, "collect: relinking\n"); + fprintf (stderr, _("collect: relinking\n")); exit = tlink_execute ("ld", ld_argv, ldout); } }