OSDN Git Service

* tlink.c (scan_linker_output): Call fclose() for opened files.
[pf3gnuchains/gcc-fork.git] / gcc / tlink.c
1 /* Scan linker error messages for missing template instantiations and provide
2    them.
3
4    Copyright (C) 1995 Free Software Foundation, Inc.
5    Contributed by Jason Merrill (jason@cygnus.com).
6
7 This file is part of GNU CC.
8
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING.  If not, write to
21 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
22
23 #include <stdio.h>
24 #include <ctype.h>
25 #include "config.h"
26 #include "hash.h"
27 #include "demangle.h"
28
29 #define MAX_ITERATIONS 17
30
31 /* Obstack allocation and deallocation routines.  */
32 #define obstack_chunk_alloc xmalloc
33 #define obstack_chunk_free free
34
35 extern char * xmalloc PARAMS((unsigned));
36 extern void free ();
37 extern char * getenv ();
38
39 /* Defined in collect2.c.  */
40 extern int vflag, debug;
41 extern char *ldout;
42 extern char *c_file_name;
43 extern struct obstack temporary_obstack;
44 extern struct obstack permanent_obstack;
45 extern char * temporary_firstobj;
46
47 /* Defined in the automatically-generated underscore.c.  */
48 extern int prepends_underscore;
49
50 static int tlink_verbose;
51 \f
52 /* Hash table code.  */
53
54 typedef struct symbol_hash_entry
55 {
56   struct hash_entry root;
57   struct file_hash_entry *file;
58   int chosen;
59   int tweaking;
60   int tweaked;
61 } symbol;
62
63 typedef struct file_hash_entry
64 {
65   struct hash_entry root;
66   const char *args;
67   const char *dir;
68   const char *main;
69   int tweaking;
70 } file;
71
72 typedef struct demangled_hash_entry
73 {
74   struct hash_entry root;
75   const char *mangled;
76 } demangled;
77
78 static struct hash_table symbol_table;
79
80 static struct hash_entry *
81 symbol_hash_newfunc (entry, table, string)
82      struct hash_entry *entry;
83      struct hash_table *table;
84      const char *string;
85 {
86   struct symbol_hash_entry *ret = (struct symbol_hash_entry *) entry;
87   if (ret == NULL)
88     {
89       ret = ((struct symbol_hash_entry *)
90              hash_allocate (table, sizeof (struct symbol_hash_entry)));
91       if (ret == NULL)
92         return NULL;
93     }
94   ret = ((struct symbol_hash_entry *)
95          hash_newfunc ((struct hash_entry *) ret, table, string));
96   ret->file = NULL;
97   ret->chosen = 0;
98   ret->tweaking = 0;
99   ret->tweaked = 0;
100   return (struct hash_entry *) ret;
101 }
102
103 static struct symbol_hash_entry *
104 symbol_hash_lookup (string, create)
105      const char *string;
106      boolean create;
107 {
108   return ((struct symbol_hash_entry *)
109           hash_lookup (&symbol_table, string, create, true));
110 }
111
112 static struct hash_table file_table;
113
114 static struct hash_entry *
115 file_hash_newfunc (entry, table, string)
116      struct hash_entry *entry;
117      struct hash_table *table;
118      const char *string;
119 {
120    struct file_hash_entry *ret = (struct file_hash_entry *) entry;
121   if (ret == NULL)
122     {
123       ret = ((struct file_hash_entry *)
124              hash_allocate (table, sizeof (struct file_hash_entry)));
125       if (ret == NULL)
126         return NULL;
127     }
128   ret = ((struct file_hash_entry *)
129          hash_newfunc ((struct hash_entry *) ret, table, string));
130   ret->args = NULL;
131   ret->dir = NULL;
132   ret->main = NULL;
133   ret->tweaking = 0;
134   return (struct hash_entry *) ret;
135 }
136
137 static struct file_hash_entry *
138 file_hash_lookup (string)
139      const char *string;
140 {
141   return ((struct file_hash_entry *)
142           hash_lookup (&file_table, string, true, true));
143 }
144
145 static struct hash_table demangled_table;
146
147 static struct hash_entry *
148 demangled_hash_newfunc (entry, table, string)
149      struct hash_entry *entry;
150      struct hash_table *table;
151      const char *string;
152 {
153   struct demangled_hash_entry *ret = (struct demangled_hash_entry *) entry;
154   if (ret == NULL)
155     {
156       ret = ((struct demangled_hash_entry *)
157              hash_allocate (table, sizeof (struct demangled_hash_entry)));
158       if (ret == NULL)
159         return NULL;
160     }
161   ret = ((struct demangled_hash_entry *)
162          hash_newfunc ((struct hash_entry *) ret, table, string));
163   ret->mangled = NULL;
164   return (struct hash_entry *) ret;
165 }
166
167 static struct demangled_hash_entry *
168 demangled_hash_lookup (string, create)
169      const char *string;
170      boolean create;
171 {
172   return ((struct demangled_hash_entry *)
173           hash_lookup (&demangled_table, string, create, true));
174 }
175 \f
176 /* Stack code.  */
177
178 struct symbol_stack_entry
179 {
180   symbol *value;
181   struct symbol_stack_entry *next;
182 };
183 struct obstack symbol_stack_obstack;
184 struct symbol_stack_entry *symbol_stack;
185
186 struct file_stack_entry
187 {
188   file *value;
189   struct file_stack_entry *next;
190 };
191 struct obstack file_stack_obstack;
192 struct file_stack_entry *file_stack;
193
194 static void
195 symbol_push (p)
196      symbol *p;
197 {
198   struct symbol_stack_entry *ep = (struct symbol_stack_entry *) obstack_alloc
199     (&symbol_stack_obstack, sizeof (struct symbol_stack_entry));
200   ep->value = p;
201   ep->next = symbol_stack;
202   symbol_stack = ep;
203 }
204
205 static symbol *
206 symbol_pop ()
207 {
208   struct symbol_stack_entry *ep = symbol_stack;
209   symbol *p;
210   if (ep == NULL)
211     return NULL;
212   p = ep->value;
213   symbol_stack = ep->next;
214   obstack_free (&symbol_stack_obstack, ep);
215   return p;
216 }
217
218 static void
219 file_push (p)
220      file *p;
221 {
222   struct file_stack_entry *ep;
223
224   if (p->tweaking)
225     return;
226
227   ep = (struct file_stack_entry *) obstack_alloc
228     (&file_stack_obstack, sizeof (struct file_stack_entry));
229   ep->value = p;
230   ep->next = file_stack;
231   file_stack = ep;
232   p->tweaking = 1;
233 }
234
235 static file *
236 file_pop ()
237 {
238   struct file_stack_entry *ep = file_stack;
239   file *p;
240   if (ep == NULL)
241     return NULL;
242   p = ep->value;
243   file_stack = ep->next;
244   obstack_free (&file_stack_obstack, ep);
245   p->tweaking = 0;
246   return p;
247 }
248 \f
249 /* Other machinery.  */
250
251 static void
252 tlink_init ()
253 {
254   char *p;
255
256   hash_table_init (&symbol_table, symbol_hash_newfunc);
257   hash_table_init (&file_table, file_hash_newfunc);
258   hash_table_init (&demangled_table, demangled_hash_newfunc);
259   obstack_begin (&symbol_stack_obstack, 0);
260   obstack_begin (&file_stack_obstack, 0);
261
262   p = getenv ("TLINK_VERBOSE");
263   if (p)
264     tlink_verbose = atoi (p);
265   else
266     {
267       tlink_verbose = 1;
268       if (vflag)
269         tlink_verbose = 2;
270       if (debug)
271         tlink_verbose = 3;
272     }
273 }
274
275 static int
276 tlink_execute (prog, argv, redir)
277      char *prog;
278      char **argv;
279      char *redir;
280 {
281   collect_execute (prog, argv, redir);
282   return collect_wait (prog);
283
284
285 static char *
286 frob_extension (s, ext)
287      char *s, *ext;
288 {
289   char *p = (char *) rindex (s, '/');
290   if (! p)
291     p = s;
292   p = (char *) rindex (p, '.');
293   if (! p)
294     p = s + strlen (s);
295
296   obstack_grow (&temporary_obstack, s, p - s);
297   return obstack_copy0 (&temporary_obstack, ext, strlen (ext));
298 }
299
300 static char *
301 obstack_fgets (stream, ob)
302      FILE *stream;
303      struct obstack *ob;
304 {
305   int c;
306   while ((c = getc (stream)) != EOF && c != '\n')
307     obstack_1grow (ob, c);
308   if (obstack_object_size (ob) == 0)
309     return NULL;
310   obstack_1grow (ob, '\0');
311   return obstack_finish (ob);
312 }
313
314 static char *
315 tfgets (stream)
316      FILE *stream;
317 {
318   return obstack_fgets (stream, &temporary_obstack);
319 }
320
321 static char *
322 pfgets (stream)
323      FILE *stream;
324 {
325   return obstack_fgets (stream, &permanent_obstack);
326 }
327 \f
328 /* Real tlink code.  */
329
330 static void
331 freadsym (stream, f, chosen)
332      FILE *stream;
333      file *f;
334      int chosen;
335 {
336   symbol *sym;
337
338   {
339     char *name = tfgets (stream);
340     sym = symbol_hash_lookup (name, true);
341   }
342
343   if (sym->file == NULL)
344     {
345       symbol_push (sym);
346       sym->file = f;
347       sym->chosen = chosen;
348     }
349   else if (chosen)
350     {
351       if (sym->chosen && sym->file != f)
352         {
353           if (sym->chosen == 1)
354             file_push (sym->file);
355           else
356             {
357               file_push (f);
358               f = sym->file;
359               chosen = sym->chosen;
360             }
361         }
362       sym->file = f;
363       sym->chosen = chosen;
364     }
365 }
366
367 static void
368 read_repo_file (f)
369      file *f;
370 {
371   char c;
372   FILE *stream = fopen (f->root.string, "r");
373
374   if (tlink_verbose >= 2)
375     fprintf (stderr, "collect: reading %s\n", f->root.string);
376
377   while (fscanf (stream, "%c ", &c) == 1)
378     {
379       switch (c)
380         {
381         case 'A':
382           f->args = pfgets (stream);
383           break;
384         case 'D':
385           f->dir = pfgets (stream);
386           break;
387         case 'M':
388           f->main = pfgets (stream);
389           break;
390         case 'P':
391           freadsym (stream, f, 2);
392           break;
393         case 'C':
394           freadsym (stream, f, 1);
395           break;
396         case 'O':
397           freadsym (stream, f, 0);
398           break;
399         }
400       obstack_free (&temporary_obstack, temporary_firstobj);
401     }
402   fclose (stream);
403   if (f->args == NULL)
404     f->args = getenv ("COLLECT_GCC_OPTIONS");
405   if (f->dir == NULL)
406     f->dir = ".";
407 }
408
409 static void
410 maybe_tweak (line, f)
411      char *line;
412      file *f;
413 {
414   symbol *sym = symbol_hash_lookup (line + 2, false);
415
416   if ((sym->file == f && sym->tweaking)
417       || (sym->file != f && line[0] == 'C'))
418     {
419       sym->tweaking = 0;
420       sym->tweaked = 1;
421
422       if (line[0] == 'O')
423         line[0] = 'C';
424       else
425         line[0] = 'O';
426     }
427 }
428
429 static int
430 recompile_files ()
431 {
432   file *f;
433
434   while ((f = file_pop ()) != NULL)
435     {
436       char *line, *command;
437       FILE *stream = fopen (f->root.string, "r");
438       char *outname = frob_extension (f->root.string, ".rnw");
439       FILE *output = fopen (outname, "w");
440
441       while ((line = tfgets (stream)) != NULL)
442         {
443           switch (line[0])
444             {
445             case 'C':
446             case 'O':
447               maybe_tweak (line, f);
448             }
449           fprintf (output, "%s\n", line);
450         }
451       fclose (stream);
452       fclose (output);
453       rename (outname, f->root.string);
454
455       obstack_grow (&temporary_obstack, "cd ", 3);
456       obstack_grow (&temporary_obstack, f->dir, strlen (f->dir));
457       obstack_grow (&temporary_obstack, "; ", 2);
458       obstack_grow (&temporary_obstack, c_file_name, strlen (c_file_name));
459       obstack_1grow (&temporary_obstack, ' ');
460       obstack_grow (&temporary_obstack, f->args, strlen (f->args));
461       obstack_1grow (&temporary_obstack, ' ');
462       command = obstack_copy0 (&temporary_obstack, f->main, strlen (f->main));
463
464       if (tlink_verbose)
465         fprintf (stderr, "collect: recompiling %s\n", f->main);
466       if (tlink_verbose >= 3)
467         fprintf (stderr, "%s\n", command);
468
469       if (system (command) != 0)
470         return 0;
471
472       read_repo_file (f);
473
474       obstack_free (&temporary_obstack, temporary_firstobj);
475     }
476   return 1;
477 }
478
479 static int
480 read_repo_files (object_lst)
481      char **object_lst;
482 {
483   char **object = object_lst;
484
485   for (; *object; object++)
486     {
487       char *p = frob_extension (*object, ".rpo");
488       file *f;
489
490       if (! file_exists (p))
491         continue;
492
493       f = file_hash_lookup (p);
494
495       read_repo_file (f);
496     }
497
498   if (file_stack != NULL && ! recompile_files ())
499     return 0;
500
501   return (symbol_stack != NULL);
502 }
503
504 static void
505 demangle_new_symbols ()
506 {
507   symbol *sym;
508
509   while ((sym = symbol_pop ()) != NULL)
510     {
511       demangled *dem;
512       char *p = cplus_demangle (sym->root.string, DMGL_PARAMS | DMGL_ANSI);
513
514       if (! p)
515         continue;
516
517       dem = demangled_hash_lookup (p, true);
518       dem->mangled = sym->root.string;
519     }
520 }
521
522 static int
523 scan_linker_output (fname)
524      char *fname;
525 {
526   FILE *stream = fopen (fname, "r");
527   char *line;
528
529   while ((line = tfgets (stream)) != NULL)
530     {
531       char *p = line, *q;
532       symbol *sym;
533       int end;
534       
535       while (*p && isspace (*p))
536         ++p;
537
538       if (! *p)
539         continue;
540
541       for (q = p; *q && ! isspace (*q); ++q)
542         ;
543
544       /* Try the first word on the line.  */
545       if (*p == '.')
546         ++p;
547       if (*p == '_' && prepends_underscore)
548         ++p;
549
550       end = ! *q;
551       *q = 0;
552       sym = symbol_hash_lookup (p, false);
553
554       if (! sym && ! end)
555         /* Try a mangled name in `quotes'.  */
556         {
557           demangled *dem = 0;
558           p = (char *) index (q+1, '`');
559           q = 0;
560
561 #define MUL "multiple definition of "
562 #define UND "undefined reference to "
563
564           if (p && (p - line > sizeof (MUL)))
565             {
566               char *beg = p - sizeof (MUL) + 1;
567               *p = 0;
568               if (!strcmp (beg, MUL) || !strcmp (beg, UND))
569                 p++, q = (char *) index (p, '\'');
570             }
571           if (q)
572             *q = 0, dem = demangled_hash_lookup (p, false);
573           if (dem)
574             sym = symbol_hash_lookup (dem->mangled, false);
575         }
576
577       if (sym && sym->tweaked)
578         {
579           fclose (stream);
580           return 0;
581         }
582       if (sym && !sym->tweaking)
583         {
584           if (tlink_verbose >= 2)
585             fprintf (stderr, "collect: tweaking %s in %s\n",
586                      sym->root.string, sym->file->root.string);
587           sym->tweaking = 1;
588           file_push (sym->file);
589         }
590         
591       obstack_free (&temporary_obstack, temporary_firstobj);
592     }
593
594   fclose (stream);
595   return (file_stack != NULL);
596 }
597
598 void
599 do_tlink (ld_argv, object_lst)
600      char **ld_argv, **object_lst;
601 {
602   int exit = tlink_execute ("ld", ld_argv, ldout);
603
604   tlink_init ();
605
606   if (exit)
607     {
608       int i = 0;
609
610       /* Until collect does a better job of figuring out which are object
611          files, assume that everything on the command line could be.  */
612       if (read_repo_files (ld_argv))
613         while (exit && i++ < MAX_ITERATIONS)
614           {
615             if (tlink_verbose >= 3)
616               dump_file (ldout);
617             demangle_new_symbols ();
618             if (! scan_linker_output (ldout))
619               break;
620             if (! recompile_files ())
621               break;
622             if (tlink_verbose)
623               fprintf (stderr, "collect: relinking\n");
624             exit = tlink_execute ("ld", ld_argv, ldout);
625           }
626     }
627
628   dump_file (ldout);
629   unlink (ldout);
630   if (exit)
631     {
632       error ("ld returned %d exit status", exit);
633       collect_exit (exit);
634     }
635 }