diff options
Diffstat (limited to 'contrib/gcc/tlink.c')
-rw-r--r-- | contrib/gcc/tlink.c | 732 |
1 files changed, 0 insertions, 732 deletions
diff --git a/contrib/gcc/tlink.c b/contrib/gcc/tlink.c deleted file mode 100644 index 882c1ab2a75e..000000000000 --- a/contrib/gcc/tlink.c +++ /dev/null @@ -1,732 +0,0 @@ -/* Scan linker error messages for missing template instantiations and provide - them. - - Copyright (C) 1995, 1998 Free Software Foundation, Inc. - Contributed by Jason Merrill (jason@cygnus.com). - -This file is part of GNU CC. - -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. - -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. - -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, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include "config.h" -#include "system.h" -#include "hash.h" -#include "demangle.h" -#include "toplev.h" -#include "collect2.h" - -#define MAX_ITERATIONS 17 - -/* Obstack allocation and deallocation routines. */ -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - -/* 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 boilerplate for working with hash.[ch]. We have hash tables - for symbol names, file names, and demangled symbols. */ - -typedef struct symbol_hash_entry -{ - struct hash_entry root; - struct file_hash_entry *file; - int chosen; - int tweaking; - int tweaked; -} symbol; - -typedef struct file_hash_entry -{ - struct hash_entry root; - const char *args; - const char *dir; - const char *main; - int tweaking; -} file; - -typedef struct demangled_hash_entry -{ - struct hash_entry root; - const char *mangled; -} demangled; - -static struct hash_table symbol_table; - -static struct hash_entry * symbol_hash_newfunc PARAMS ((struct hash_entry *, - struct hash_table *, - hash_table_key)); -static struct symbol_hash_entry * symbol_hash_lookup PARAMS ((const char *, - boolean)); -static struct hash_entry * file_hash_newfunc PARAMS ((struct hash_entry *, - struct hash_table *, - hash_table_key)); -static struct file_hash_entry * file_hash_lookup PARAMS ((const char *)); -static struct hash_entry * demangled_hash_newfunc PARAMS ((struct hash_entry *, - struct hash_table *, - hash_table_key)); -static struct demangled_hash_entry * - demangled_hash_lookup PARAMS ((const char *, boolean)); -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 ((char *, char **, char *)); -static char * frob_extension PARAMS ((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 *)); - -/* Create a new entry for the symbol hash table. - Passed to hash_table_init. */ - -static struct hash_entry * -symbol_hash_newfunc (entry, table, string) - struct hash_entry *entry; - struct hash_table *table; - hash_table_key string; -{ - 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->file = NULL; - ret->chosen = 0; - ret->tweaking = 0; - ret->tweaked = 0; - return (struct hash_entry *) ret; -} - -/* Look up an entry in the symbol hash table. */ - -static struct symbol_hash_entry * -symbol_hash_lookup (string, create) - const char *string; - boolean create; -{ - return ((struct symbol_hash_entry *) - hash_lookup (&symbol_table, (hash_table_key) string, - create, &string_copy)); -} - -static struct hash_table file_table; - -/* Create a new entry for the file hash table. - Passed to hash_table_init. */ - -static struct hash_entry * -file_hash_newfunc (entry, table, string) - struct hash_entry *entry; - struct hash_table *table; - hash_table_key string; -{ - struct file_hash_entry *ret = (struct file_hash_entry *) entry; - if (ret == NULL) - { - ret = ((struct file_hash_entry *) - hash_allocate (table, sizeof (struct file_hash_entry))); - if (ret == NULL) - return NULL; - } - ret->args = NULL; - ret->dir = NULL; - ret->main = NULL; - ret->tweaking = 0; - return (struct hash_entry *) ret; -} - -/* Look up an entry in the file hash table. */ - -static struct file_hash_entry * -file_hash_lookup (string) - const char *string; -{ - return ((struct file_hash_entry *) - hash_lookup (&file_table, (hash_table_key) string, true, - &string_copy)); -} - -static struct hash_table demangled_table; - -/* Create a new entry for the demangled name hash table. - Passed to hash_table_init. */ - -static struct hash_entry * -demangled_hash_newfunc (entry, table, string) - struct hash_entry *entry; - struct hash_table *table; - hash_table_key string; -{ - struct demangled_hash_entry *ret = (struct demangled_hash_entry *) entry; - if (ret == NULL) - { - ret = ((struct demangled_hash_entry *) - hash_allocate (table, sizeof (struct demangled_hash_entry))); - if (ret == NULL) - return NULL; - } - ret->mangled = NULL; - return (struct hash_entry *) ret; -} - -/* 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; -{ - return ((struct demangled_hash_entry *) - hash_lookup (&demangled_table, (hash_table_key) string, - create, &string_copy)); -} - -/* Stack code. */ - -struct symbol_stack_entry -{ - symbol *value; - struct symbol_stack_entry *next; -}; -struct obstack symbol_stack_obstack; -struct symbol_stack_entry *symbol_stack; - -struct file_stack_entry -{ - file *value; - struct file_stack_entry *next; -}; -struct obstack file_stack_obstack; -struct file_stack_entry *file_stack; - -static void -symbol_push (p) - symbol *p; -{ - struct symbol_stack_entry *ep = (struct symbol_stack_entry *) obstack_alloc - (&symbol_stack_obstack, sizeof (struct symbol_stack_entry)); - ep->value = p; - ep->next = symbol_stack; - symbol_stack = ep; -} - -static symbol * -symbol_pop () -{ - struct symbol_stack_entry *ep = symbol_stack; - symbol *p; - if (ep == NULL) - return NULL; - p = ep->value; - symbol_stack = ep->next; - obstack_free (&symbol_stack_obstack, ep); - return p; -} - -static void -file_push (p) - file *p; -{ - struct file_stack_entry *ep; - - if (p->tweaking) - return; - - ep = (struct file_stack_entry *) obstack_alloc - (&file_stack_obstack, sizeof (struct file_stack_entry)); - ep->value = p; - ep->next = file_stack; - file_stack = ep; - p->tweaking = 1; -} - -static file * -file_pop () -{ - struct file_stack_entry *ep = file_stack; - file *p; - if (ep == NULL) - return NULL; - p = ep->value; - file_stack = ep->next; - obstack_free (&file_stack_obstack, ep); - p->tweaking = 0; - return p; -} - -/* Other machinery. */ - -/* Initialize the tlink machinery. Called from do_tlink. */ - -static void -tlink_init () -{ - char *p; - - hash_table_init (&symbol_table, symbol_hash_newfunc, &string_hash, - &string_compare); - hash_table_init (&file_table, file_hash_newfunc, &string_hash, - &string_compare); - hash_table_init (&demangled_table, demangled_hash_newfunc, - &string_hash, &string_compare); - obstack_begin (&symbol_stack_obstack, 0); - obstack_begin (&file_stack_obstack, 0); - - p = getenv ("TLINK_VERBOSE"); - if (p) - tlink_verbose = atoi (p); - else - { - tlink_verbose = 1; - if (vflag) - tlink_verbose = 2; - if (debug) - tlink_verbose = 3; - } -} - -static int -tlink_execute (prog, argv, redir) - char *prog; - char **argv; - char *redir; -{ - collect_execute (prog, argv, redir); - return collect_wait (prog); -} - -static char * -frob_extension (s, ext) - char *s; - const char *ext; -{ - char *p = rindex (s, '/'); - if (! p) - p = s; - p = rindex (p, '.'); - if (! p) - p = s + strlen (s); - - obstack_grow (&temporary_obstack, s, p - s); - return obstack_copy0 (&temporary_obstack, ext, strlen (ext)); -} - -static char * -obstack_fgets (stream, ob) - FILE *stream; - struct obstack *ob; -{ - int c; - while ((c = getc (stream)) != EOF && c != '\n') - obstack_1grow (ob, c); - if (obstack_object_size (ob) == 0) - return NULL; - obstack_1grow (ob, '\0'); - return obstack_finish (ob); -} - -static char * -tfgets (stream) - FILE *stream; -{ - return obstack_fgets (stream, &temporary_obstack); -} - -static char * -pfgets (stream) - FILE *stream; -{ - return obstack_fgets (stream, &permanent_obstack); -} - -/* 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; - file *f; - int chosen; -{ - symbol *sym; - - { - 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) - file_push (sym->file); - else - { - file_push (f); - f = sym->file; - chosen = sym->chosen; - } - } - sym->file = f; - sym->chosen = 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 ((char*) f->root.key, "r"); - - if (tlink_verbose >= 2) - fprintf (stderr, "collect: reading %s\n", - (char*) f->root.key); - - while (fscanf (stream, "%c ", &c) == 1) - { - switch (c) - { - case 'A': - f->args = pfgets (stream); - break; - case 'D': - f->dir = pfgets (stream); - break; - case 'M': - f->main = pfgets (stream); - break; - case 'P': - freadsym (stream, f, 2); - break; - case 'C': - freadsym (stream, f, 1); - break; - case 'O': - freadsym (stream, f, 0); - break; - } - obstack_free (&temporary_obstack, temporary_firstobj); - } - fclose (stream); - if (f->args == NULL) - f->args = getenv ("COLLECT_GCC_OPTIONS"); - if (f->dir == NULL) - 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; - file *f; -{ - symbol *sym = symbol_hash_lookup (line + 2, false); - - if ((sym->file == f && sym->tweaking) - || (sym->file != f && line[0] == 'C')) - { - sym->tweaking = 0; - sym->tweaked = 1; - - if (line[0] == 'O') - line[0] = 'C'; - else - line[0] = 'O'; - } -} - -/* 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; - - while ((f = file_pop ()) != NULL) - { - char *line, *command; - FILE *stream = fopen ((char*) f->root.key, "r"); - char *outname = frob_extension ((char*) f->root.key, ".rnw"); - FILE *output = fopen (outname, "w"); - - while ((line = tfgets (stream)) != NULL) - { - switch (line[0]) - { - case 'C': - case 'O': - maybe_tweak (line, f); - } - fprintf (output, "%s\n", line); - } - fclose (stream); - fclose (output); - rename (outname, (char*) f->root.key); - - obstack_grow (&temporary_obstack, "cd ", 3); - obstack_grow (&temporary_obstack, f->dir, strlen (f->dir)); - obstack_grow (&temporary_obstack, "; ", 2); - obstack_grow (&temporary_obstack, c_file_name, strlen (c_file_name)); - obstack_1grow (&temporary_obstack, ' '); - obstack_grow (&temporary_obstack, f->args, strlen (f->args)); - obstack_1grow (&temporary_obstack, ' '); - command = obstack_copy0 (&temporary_obstack, f->main, strlen (f->main)); - - if (tlink_verbose) - fprintf (stderr, "collect: recompiling %s\n", f->main); - if (tlink_verbose >= 3) - fprintf (stderr, "%s\n", command); - - if (system (command) != 0) - return 0; - - read_repo_file (f); - - obstack_free (&temporary_obstack, temporary_firstobj); - } - 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; -{ - char **object = object_lst; - - for (; *object; object++) - { - char *p = frob_extension (*object, ".rpo"); - file *f; - - if (! file_exists (p)) - continue; - - f = file_hash_lookup (p); - - read_repo_file (f); - } - - if (file_stack != NULL && ! recompile_files ()) - return 0; - - return (symbol_stack != NULL); -} - -/* Add the demangled forms of any new symbols to the hash table. */ - -static void -demangle_new_symbols () -{ - symbol *sym; - - while ((sym = symbol_pop ()) != NULL) - { - demangled *dem; - char *p = cplus_demangle ((char*) sym->root.key, - DMGL_PARAMS | DMGL_ANSI); - - if (! p) - continue; - - dem = demangled_hash_lookup (p, true); - dem->mangled = (char*) sym->root.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) - const char *fname; -{ - FILE *stream = fopen (fname, "r"); - char *line; - - while ((line = tfgets (stream)) != NULL) - { - char *p = line, *q; - symbol *sym; - int end; - - while (*p && ISSPACE ((unsigned char)*p)) - ++p; - - if (! *p) - continue; - - for (q = p; *q && ! ISSPACE ((unsigned char)*q); ++q) - ; - - /* Try the first word on the line. */ - if (*p == '.') - ++p; - if (*p == '_' && prepends_underscore) - ++p; - - end = ! *q; - *q = 0; - sym = symbol_hash_lookup (p, false); - - if (! sym && ! end) - /* Try a mangled name in quotes. */ - { - char *oldq = q+1; - demangled *dem = 0; - q = 0; - - /* First try `GNU style'. */ - p = index (oldq, '`'); - if (p) - p++, q = index (p, '\''); - /* Then try "double quotes". */ - else if (p = index (oldq, '"'), p) - p++, q = index (p, '"'); - - if (q) - { - *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 (sym && sym->tweaked) - { - fclose (stream); - return 0; - } - if (sym && !sym->tweaking) - { - if (tlink_verbose >= 2) - fprintf (stderr, "collect: tweaking %s in %s\n", - (char*) sym->root.key, (char*) sym->file->root.key); - sym->tweaking = 1; - file_push (sym->file); - } - - obstack_free (&temporary_obstack, temporary_firstobj); - } - - fclose (stream); - 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; -{ - int exit = tlink_execute ("ld", ld_argv, ldout); - - tlink_init (); - - if (exit) - { - int i = 0; - - /* Until collect does a better job of figuring out which are object - files, assume that everything on the command line could be. */ - if (read_repo_files (ld_argv)) - while (exit && i++ < MAX_ITERATIONS) - { - if (tlink_verbose >= 3) - dump_file (ldout); - demangle_new_symbols (); - if (! scan_linker_output (ldout)) - break; - if (! recompile_files ()) - break; - if (tlink_verbose) - fprintf (stderr, "collect: relinking\n"); - exit = tlink_execute ("ld", ld_argv, ldout); - } - } - - dump_file (ldout); - unlink (ldout); - if (exit) - { - error ("ld returned %d exit status", exit); - collect_exit (exit); - } -} |