Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / config / gtscc.c
blob638d7d6ee7f58f2a7d590330d307051df8ea31ba
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
37 /* */
39 *--------------------------------------------------------------------------
43 *--------------------------------------------------------------------------
45 * gtscc - Global To Static C/C++ compiler driver.
47 * Syntax:
49 * gtscc [options] -c file.cpp ...
50 * gtscc [options] file.o ... libxx.a ...
52 * gtscc is a compiler and linker driver/wrapper for Irix only.
53 * gtscc takes all compiler options and passes them onto the Irix
54 * cc/CC compiler/linker.
55 * Typically, gtscc is used in two phases. Phase one is during compilation.
56 * gtscc, the compiler, converts all inline globals to statics, and records
57 * the existence of other globals and how to compile the file in the gtscc
58 * database file.
59 * During linking, globals dependencies are analyzed, and a list of
60 * "convertable" globals is determined. Globals that are not referenced
61 * globally, but are referenced locally are considered convertable.
62 * The linker then recompiles the files that those symbols are in, and
63 * converts them to statics. It also calls the archiver to install
64 * the converted objects into libraries.
65 * Finally the linker is called.
67 * Created: David Williams, djw@netscape.com, 13-Feb-1997
69 *--------------------------------------------------------------------------
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <sys/types.h>
75 #include <sys/wait.h>
76 #include <sys/param.h>
77 #include <sys/types.h>
78 #include <unistd.h>
79 #include <ctype.h>
81 #if defined(LINUX) && defined(__GLIBC__)
82 #include <libelf/libelf.h>
83 #else
84 #include <libelf.h>
85 #endif
87 #include <sys/stat.h>
88 #include <fcntl.h>
89 #include <sys/time.h>
91 #define DEFAULT_MAX_GLOBALS 15500
93 #define ELFSYM_IS_DEFINED(x) ((x).st_shndx != SHN_UNDEF)
94 #define ELFSYM_IS_UNDEFINED(x) ((x).st_shndx == SHN_UNDEF)
96 #ifdef IRIX
97 #define CC_COMMAND "cc"
98 #define CCC_COMMAND "CC"
99 #define AS_COMMAND "cc"
100 #define LD_COMMAND "CC"
101 #define AR_COMMAND "ar"
102 #define AR_OPTIONS "cr"
103 #else
104 #define HANDLES_DASHSO
105 #define CC_COMMAND "gcc"
106 #define CCC_COMMAND "g++"
107 #define AS_COMMAND "gcc"
108 #define LD_COMMAND "g++"
109 #define AR_COMMAND "ar"
110 #define AR_OPTIONS "cr"
111 #endif
113 #define EH_NEW(type) (type*)malloc(sizeof(type))
115 #define TRUE 1
116 #define FALSE 0
118 #define EH_TAG_FILE 'F'
119 #define EH_TAG_GLOBAL 'G'
120 #define EH_TAG_ZAPPED 'Z'
121 #define EH_TAG_INLINE 'I'
122 #define EH_TAG_UNDEFINED 'U'
124 #define VERBOSITY_USER(x) ((x) > 0)
125 #define VERBOSITY_DEBUG(x) ((x) > 1)
126 #define VERBOSITY_MAJOR(x) ((x) > 2)
128 static char eh_unnamed_object[] = "<name not known>";
130 typedef struct {
131 char* name; /* archive */
132 } EhArchive;
134 typedef struct {
135 char* name; /* name of C/C++ file, relative to rootdir */
136 char* directory;/* must compile in this directory */
137 char** cc_args; /* cc -I ..... */
138 char* as_savefile;
139 time_t compile_time;
140 char* target_object;
141 } EhSource;
143 typedef struct EhObject {
144 struct EhObject* _recompile; /* used for recompilation link list */
145 unsigned _needs_unzap;
146 char* name; /* name of .o */
147 EhArchive* archive; /* it is stored in */
148 EhSource* source;
149 char* pathname;
150 unsigned nusers;
151 } EhObject;
153 typedef enum {
154 EH_SYM_UNDEFINED,
155 EH_SYM_DEFINED,
156 EH_SYM_ZAPPED,
157 EH_SYM_INLINE /* are treated special - they belong to no file */
158 } EhSymState;
160 typedef struct EhSym {
161 struct EhSym* _next; /* used for link list */
162 char* name; /* name of symbol */
163 EhObject* object; /* if symbol is undefined == NULL */
164 unsigned ngusers; /* number of global users */
165 unsigned nlusers; /* number of local file users */
167 #if 0
168 unsigned section; /* section in elf file */
169 unsigned index; /* index into symbol table */
170 unsigned char info;
171 unsigned dirty;
172 #endif
173 EhSymState state;
174 } EhSym;
176 #define EHSYM_ISDEFINED(x) ((x)->object!=NULL && (x)->state==EH_SYM_DEFINED)
177 #define EHSYM_ISZAPPED(x) ((x)->object!=NULL && (x)->state==EH_SYM_ZAPPED)
178 #define EHSYM_ISUNDEFINED(x) ((x)->object == NULL)
179 #define EHSYM_ISUSED(x) ((x)->nusers != 0)
180 #define EHSYM_ISINLINE(x) ((x)->state == EH_SYM_INLINE)
182 #define EH_OBJECT_CANBUILD(x) \
183 ((x)->source != NULL && (x)->name != eh_unnamed_object)
185 #define USE_HASHING
187 typedef struct {
188 #ifdef USE_HASHING
189 EhSym** heads;
190 unsigned size;
191 #else
192 EhSym* head;
193 #endif
194 unsigned nentries;
195 } EhSymTable;
197 static char*
198 make_relative_pathname(char* buf, char* filename, char* rootdir)
200 char buf1[MAXPATHLEN];
201 char buf2[MAXPATHLEN];
202 char* p;
203 char* q;
205 if (rootdir == NULL) {
206 strcpy(buf, filename);
207 return filename;
210 if (filename[0] != '/') {
211 if (getcwd(buf2, sizeof(buf2)) == NULL) {
212 fprintf(stderr, "cannot get pwd\n");
213 return NULL;
216 strcat(buf2, "/");
217 strcat(buf2, filename);
219 filename = buf2;
222 if (realpath(filename, buf1) == NULL) {
223 fprintf(stderr, "realpath(%s,..) failed\n", filename);
224 return NULL;
227 if (realpath(rootdir, buf2) == NULL) {
228 fprintf(stderr, "realpath(%s,..) failed\n", rootdir);
229 return NULL;
232 strcat(buf2, "/");
234 for (p = buf1, q = buf2; *p == *q; p++, q++)
237 strcpy(buf, p);
239 return buf;
242 static EhArchive*
243 EhArchiveNew(char* name, char* rootdir)
245 EhArchive* archive = EH_NEW(EhArchive);
246 char pathbuf[MAXPATHLEN];
248 make_relative_pathname(pathbuf, name, rootdir);
250 archive->name = strdup(pathbuf);
252 return archive;
255 #if 0
257 * This is evil, we should never free anything, because it messes up
258 * interning.
260 static void
261 EhSourceDelete(EhSource* source)
263 unsigned n;
264 if (source->name != NULL)
265 free(source->name);
266 if (source->directory != NULL)
267 free(source->directory);
268 if (source->cc_args != NULL) {
269 for (n = 0; source->cc_args[n] != NULL; n++)
270 free(source->cc_args[n]);
271 free(source->cc_args);
273 if (source->as_savefile != NULL)
274 free(source->as_savefile);
276 #endif
278 static EhSource*
279 EhSourceNew(char* name, char** cc_args, char* directory)
281 EhSource* source = EH_NEW(EhSource);
282 unsigned n;
283 unsigned m;
285 source->name = strdup(name);
286 source->directory = (directory != NULL)? strdup(directory): NULL;
287 source->as_savefile = NULL;
288 source->compile_time = 0;
289 source->target_object = NULL;
290 source->cc_args = NULL;
292 if (cc_args != NULL) {
294 for (n = 0; cc_args[n] != NULL; n++)
297 source->cc_args = (char**)malloc(sizeof(char*) * (n+1));
299 for (m = 0, n = 0; cc_args[n] != NULL;) {
300 if (strcmp(cc_args[n], "-o") == 0 && cc_args[n+1] != NULL) {
301 source->target_object = strdup(cc_args[n+1]);
302 n += 2;
303 } else {
304 source->cc_args[m++] = strdup(cc_args[n++]);
308 source->cc_args[m] = NULL;
311 return source;
314 static EhObject*
315 EhObjectNewArchiveObject(EhArchive* archive, char* name)
317 EhObject* object = EH_NEW(EhObject);
319 if (name == eh_unnamed_object)
320 object->name = name;
321 else
322 object->name = strdup(name);
323 object->archive = archive;
324 object->source = NULL;
325 object->_recompile = NULL;
326 object->_needs_unzap = 0;
327 object->pathname = NULL;
328 object->nusers = 0;
330 return object;
333 static EhObject*
334 EhObjectNew(char* name, char* rootdir)
336 EhObject* object = EhObjectNewArchiveObject(NULL, name);
337 char pathname[MAXPATHLEN];
339 make_relative_pathname(pathname, name, rootdir);
340 object->pathname = strdup(pathname);
342 return object;
345 static EhObject*
346 EhObjectNewFromSource(EhSource* source)
348 EhObject* object = EhObjectNewArchiveObject(NULL, eh_unnamed_object);
350 object->source = source;
352 return object;
355 static char*
356 EhObjectGetFilename(EhObject* object, char* buf)
358 if (object->archive) {
359 strcpy(buf, object->archive->name);
360 strcat(buf, ":");
361 strcat(buf, object->name);
362 return buf;
363 } else {
364 return object->name;
368 static EhSym*
369 EhSymNewDefined(char* name, EhObject* object)
371 EhSym* sym = EH_NEW(EhSym);
373 sym->name = strdup(name);
374 sym->object = object;
375 sym->state = EH_SYM_DEFINED;
376 sym->ngusers = 0;
377 sym->nlusers = 0;
379 return sym;
382 static EhSym*
383 EhSymNewInline(char* name)
385 EhSym* sym = EhSymNewDefined(name, NULL);
386 sym->state = EH_SYM_INLINE;
388 return sym;
391 static EhSym*
392 EhSymNewUndefined(char* name)
394 EhSym* sym = EhSymNewDefined(name, NULL);
395 sym->state = EH_SYM_UNDEFINED;
397 return sym;
400 static EhSym*
401 EhSymNewZapped(char* name, EhObject* object)
403 EhSym* sym = EhSymNewDefined(name, object);
404 sym->state = EH_SYM_ZAPPED;
406 return sym;
409 static EhSym*
410 EhSymNewRandomZap(char* name)
412 EhSym* sym = EhSymNewZapped(name, NULL);
414 return sym;
417 EhSymTable*
418 EhSymTableNew(unsigned p_size)
420 EhSymTable* table = EH_NEW(EhSymTable);
422 #ifdef USE_HASHING
423 unsigned size;
424 for (size = 0x1; size < (16*1024); size <<= 1) {
425 if (size >= p_size)
426 break;
428 table->size = size;
429 table->heads = (EhSym**)calloc(size, sizeof(EhSym*));
430 #else
431 table->head = NULL;
432 #endif
433 table->nentries = 0;
435 return table;
438 EhSym*
439 EhSymTableInsert(EhSymTable* table, EhSym* sym)
441 #ifdef USE_HASHING
442 unsigned long hash = elf_hash(sym->name);
443 unsigned long mask = table->size - 1;
444 unsigned index = (hash & mask);
446 sym->_next = table->heads[index];
447 table->heads[index] = sym;
448 #else
449 sym->_next = table->head;
450 table->head = sym;
451 #endif
452 table->nentries++;
454 return sym;
457 EhSym*
458 EhSymTableFind(EhSymTable* table, char* name)
460 EhSym* sym;
461 EhSym* head;
463 #ifdef USE_HASHING
464 unsigned long hash = elf_hash(name);
465 unsigned long mask = table->size - 1;
466 unsigned index = (hash & mask);
467 head = table->heads[index];
468 #else
469 head = table->head;
470 #endif
472 for (sym = head; sym != NULL; sym = sym->_next) {
473 if (strcmp(name, sym->name) == 0)
474 break;
477 return sym;
480 typedef int (*eh_dump_mappee_t)(EhSym* sym, void* arg);
482 static int
483 EhSymTableMap(EhSymTable* table, eh_dump_mappee_t func, void* arg)
485 EhSym* sym;
486 EhSym* head;
488 #ifdef USE_HASHING
489 unsigned n;
490 for (n = 0; n < table->size; n++) {
491 head = table->heads[n];
492 #else
493 head = table->head; {
494 #endif
495 for (sym = head; sym != NULL; sym = sym->_next) {
496 if ((func)(sym, arg) == -1)
497 return -1;
501 return 0;
504 typedef struct {
505 EhObject* o_old;
506 EhObject* o_new;
507 } fixup_info;
509 static int
510 fixup_mappee(EhSym* sym, void* arg)
512 fixup_info* info = (fixup_info*)arg;
514 if (sym->object == info->o_old)
515 sym->object = info->o_new;
517 return 0;
520 static EhObject*
521 EhSymTableObjectFixup(EhSymTable* table, EhObject* o_old, EhObject* o_new)
523 fixup_info info;
526 * Now visit every sym that pointed to tmp, and point it
527 * at object.
529 info.o_old = o_old;
530 info.o_new = o_new;
531 EhSymTableMap(table, fixup_mappee, &info);
533 return o_new;
538 static char*
539 safe_fgets(char* buf, unsigned size, FILE* fp)
541 unsigned nread = 0;
543 if (buf == NULL)
544 buf = (char*)malloc(size);
546 for (;;) {
548 if (fgets(&buf[nread], size - nread, fp) == NULL) {
549 free(buf);
550 return NULL;
553 if (strchr(buf, '\n') != NULL)
554 return buf;
557 * fgets returns n-1 characters and \0
559 nread += (size - nread) - 1;
560 size += 1024;
561 buf = (char*)realloc(buf, size);
565 static int
566 EhSymTableSetSymbolState(EhSymTable* table, char* name, EhSymState new_state)
568 EhSym* sym = EhSymTableFind(table, name);
570 if (sym == NULL) {
571 sym = EhSymNewDefined(name, NULL);
573 EhSymTableInsert(table, sym);
576 /* new_state must be EH_SYM_DEFINED || EH_SYM_ZAPPED */
577 if (sym->state == EH_SYM_DEFINED || sym->state == EH_SYM_ZAPPED) {
578 sym->state = new_state;
579 } else if (sym->state == EH_SYM_INLINE) {
580 char* state_name;
581 if (new_state == EH_SYM_DEFINED)
582 state_name = "global";
583 else
584 state_name = "static";
585 fprintf(stderr,
586 "WARNING: Symbol %s is an inline.\n"
587 " Forcing the symbol %s will be ignored.\n",
588 name,
589 state_name);
590 } else { /* EH_SYM_UNDEFINED */
592 * This call is being made after objects have started being
593 * read. This is too late. I'm not sure I care though.
595 return -1;
598 return 0;
601 static int
602 EhSymTableFpLoad(EhSymTable* table, FILE* fp)
604 char* buf = NULL; /* I hope this is big enough */
605 char* p;
606 char* name;
607 char* state;
608 EhSym* sym;
609 EhSource* source = NULL;
610 EhObject* object = NULL;
611 char* cc_args[512];
612 unsigned n;
613 unsigned line_n = 0;
614 char* ctime = NULL;
615 char* directory;
616 char* savefile;
618 while ((buf = safe_fgets(buf, 1024, fp)) != NULL) {
620 if ((p = strchr(buf, '\n')) == NULL) {
621 fprintf(stderr, "line to long: %d\n", line_n);
622 return -1;
624 *p = '\0';
626 line_n++;
628 if (buf[0] == '!') /* comment */
629 continue;
631 for (p = buf; isspace(*p); p++)
634 name = p;
635 for (; !isspace(*p); p++)
637 *p++ = '\0';
639 if (name[0] == '\0')
640 continue;
642 for (; isspace(*p); p++)
645 state = p;
646 for (; !isspace(*p) && *p != '\0'; p++)
648 *p++ = '\0';
650 if (state[0] == EH_TAG_GLOBAL
652 state[0] == EH_TAG_ZAPPED
654 state[0] == EH_TAG_INLINE) {
655 sym = EhSymTableFind(table, name);
656 if (sym == NULL) { /* install a new one */
658 if (source == NULL && state[0] != EH_TAG_INLINE) {
659 fprintf(stderr,
660 "[%d] found new style symbol (%s) but no source\n",
661 line_n, name);
664 if (state[0] == EH_TAG_GLOBAL)
665 sym = EhSymNewDefined(name, object);
666 else if (state[0] == EH_TAG_INLINE)
667 sym = EhSymNewInline(name);
668 else
669 sym = EhSymNewZapped(name, object);
671 EhSymTableInsert(table, sym);
672 } else {
673 if (state[0] == EH_TAG_GLOBAL) {
674 if (sym->state != EH_SYM_DEFINED) {
675 fprintf(stderr,
676 "out of sync defined symbol: %s, fixing\n",
677 sym->name);
678 sym->state = EH_SYM_DEFINED;
680 } else if (state[0] == EH_TAG_INLINE) {
681 if (sym->state != EH_SYM_INLINE) {
682 fprintf(stderr,
683 "out of sync inlined symbol: %s, fixing\n",
684 sym->name);
685 sym->state = EH_SYM_INLINE;
687 } else {
688 if (sym->state != EH_SYM_ZAPPED) {
689 fprintf(stderr,
690 "out of sync zapped symbol: %s, fixing\n",
691 sym->name);
692 sym->state = EH_SYM_ZAPPED;
696 #if 0
697 /* these are probably "special" symbols like .div */
698 if (sym->object != object) {
699 fprintf(stderr,
700 "out of sync object for symbol: %s, ignoring\n",
701 sym->name);
703 #endif
706 continue; /* no more fields we care about */
707 } else if (state[0] == EH_TAG_FILE) {
709 directory = p;
710 for (; !isspace(*p) && *p != '\0'; p++)
712 *p++ = '\0';
714 savefile = p;
715 for (; !isspace(*p) && *p != '\0'; p++)
717 *p++ = '\0';
719 ctime = p;
720 for (; !isspace(*p) && *p != '\0'; p++)
722 *p++ = '\0';
724 for (n = 0; *p != '\0';) {
726 for (; isspace(*p); p++)
729 cc_args[n++] = p++;
731 for (; !isspace(*p) && *p != '\0'; p++)
734 if (*p == '\0')
735 break;
737 *p++ = '\0';
739 cc_args[n] = NULL;
741 if (strcmp(directory, ".") == 0)
742 directory = NULL;
743 source = EhSourceNew(name, cc_args, directory);
744 if (ctime != NULL)
745 source->compile_time = (time_t)atoi(ctime);
746 object = EhObjectNewFromSource(source);
748 } else { /* old style symbol list */
749 sym = EhSymTableFind(table, name);
750 if (sym != NULL) {
751 if (sym->state != EH_SYM_ZAPPED) {
752 fprintf(stderr,
753 "out of sync random zapped symbol: %s, fixing\n",
754 sym->name);
755 sym->state = EH_SYM_ZAPPED;
757 } else {
758 sym = EhSymNewRandomZap(name);
763 return line_n;
766 typedef struct {
767 EhSym** vector;
768 unsigned index;
769 } flush_info;
771 static int
772 flush_mappee(EhSym* sym, void* arg)
774 flush_info* info = (flush_info*)arg;
776 if (sym->state == EH_SYM_INLINE
778 (sym->object != NULL && sym->state == EH_SYM_DEFINED)
780 (sym->object != NULL && sym->state == EH_SYM_ZAPPED)) {
781 if (info->vector != NULL)
782 info->vector[info->index] = sym;
783 info->index++;
786 return 0;
789 static int
790 flush_compare(const void* ap, const void* bp)
792 EhSym** ax = (EhSym**)ap;
793 EhSym** bx = (EhSym**)bp;
794 EhSym* a = *ax;
795 EhSym* b = *bx;
796 EhObject* oa = a->object;
797 EhObject* ob = b->object;
798 int foo;
800 if (oa == NULL && ob != NULL)
801 return -1;
802 if (oa != NULL && ob == NULL)
803 return 1;
804 if (oa == NULL && ob == NULL) {
805 foo = strcmp(a->name, b->name);
806 if (foo < 0)
807 return -1;
808 else if (foo > 0)
809 return 1;
810 return 0;
813 if (oa->source == NULL && ob->source != NULL)
814 return -1;
815 if (oa->source != NULL && ob->source == NULL)
816 return 1;
817 if (oa->source == ob->source)
818 return 0;
819 if (oa->source < ob->source)
820 return -1;
821 if (oa->source > ob->source)
822 return 1;
823 foo = strcmp(a->name, b->name);
824 if (foo < 0)
825 return -1;
826 else if (foo > 0)
827 return 1;
828 return 0;
831 static void
832 EhSourceFpWrite(EhSource* source, FILE* fp)
834 unsigned n = 0;
836 fputs(source->name, fp);
837 fputc(' ', fp);
838 fputc(EH_TAG_FILE, fp);
840 fputc(' ', fp);
841 if (source->directory != NULL)
842 fprintf(fp, "%s", source->directory);
843 else
844 fputc('.', fp);
846 fputc(' ', fp);
847 if (source->as_savefile != NULL)
848 fprintf(fp, "%s", source->as_savefile);
849 else
850 fputc('.', fp);
852 fputc(' ', fp);
853 fprintf(fp, "%d", source->compile_time);
855 if (source->target_object != NULL) {
856 fputs(" -o ", fp);
857 fputs(source->target_object, fp);
860 if (source->cc_args != NULL) {
861 for (n = 0; source->cc_args[n] != NULL; n++) {
862 fputc(' ', fp);
863 fputs(source->cc_args[n], fp);
867 if (n < 1)
868 fprintf(stderr, "WARNING: %s has no args\n", source->name);
870 fputc('\n', fp);
873 static int
874 EhSymTableFpDump(EhSymTable* table, FILE* fp)
876 flush_info info;
877 unsigned n;
878 EhObject* object = NULL;
879 EhSym** syms;
880 EhSym* sym;
881 unsigned size;
883 info.index = 0;
884 info.vector = NULL;
885 EhSymTableMap(table, flush_mappee, (void*)&info);
886 size = info.index;
888 syms = (EhSym**)malloc(sizeof(EhSym*) * size);
889 info.index = 0;
890 info.vector = syms;
891 EhSymTableMap(table, flush_mappee, (void*)&info);
893 /* sort */
894 qsort(syms, size, sizeof(EhSym*), flush_compare);
896 /* dump */
897 for (n = 0; n < size; n++) {
898 sym = syms[n];
900 if (sym->object != object) {
901 object = sym->object;
903 if (object->source != NULL) {
904 EhSourceFpWrite(object->source, fp);
908 if (sym->state == EH_SYM_INLINE) {
909 fprintf(fp, "%s %c\n", sym->name, EH_TAG_INLINE);
910 } else if (object->source != NULL && sym->state == EH_SYM_ZAPPED) {
911 fprintf(fp, "%s %c\n", sym->name, EH_TAG_ZAPPED);
912 } else if (object->source != NULL && sym->state == EH_SYM_DEFINED) {
913 fprintf(fp, "%s %c\n", sym->name, EH_TAG_GLOBAL);
917 free(syms);
919 return n;
922 int djw_debug;
923 char* djw_test_name;
926 eh_process_object(Elf* elf, EhObject* object, EhSymTable* table)
928 Elf32_Shdr * shdr;
929 Elf32_Ehdr * ehdr;
930 Elf_Scn * scn;
931 Elf_Data * shstr_data;
932 Elf_Data* sym_data = NULL;
933 Elf_Data* str_data = NULL;
934 Elf_Data* rel_data[4];
935 int nrel_data = 0;
936 Elf32_Rel* rel_entries;
937 Elf_Data* rela_data[10];
938 int nrela_data = 0;
939 Elf32_Rela* rela_entries;
940 unsigned int cnt;
941 Elf32_Sym* elf_sym;
942 int i;
943 int j;
944 int k;
945 char* name;
946 EhSym* sym;
947 char buf[MAXPATHLEN];
949 /* Obtain the .shstrtab data buffer */
950 if (((ehdr = elf32_getehdr(elf)) == NULL) ||
951 ((scn = elf_getscn(elf, ehdr->e_shstrndx)) == NULL) ||
952 ((shstr_data = elf_getdata(scn, NULL)) == NULL)) {
953 fprintf(stderr, "problems on %s\n", EhObjectGetFilename(object, buf));
954 return -1;
957 /* get the string table */
958 for (cnt = 1, scn = NULL; (scn = elf_nextscn(elf, scn)); cnt++) {
959 if ((shdr = elf32_getshdr(scn)) == NULL) {
960 fprintf(stderr, "problems on %s, section %d\n",
961 EhObjectGetFilename(object, buf), cnt);
962 return -1;
965 #if 0
966 fprintf(stderr, "%s: section %d type %d name %s\n",
967 EhObjectGetFilename(object, buf),
968 cnt,
969 shdr->sh_type,
970 (char*)shstr_data->d_buf + shdr->sh_name);
971 #endif
974 * Get the string table.
976 if (shdr->sh_type == SHT_STRTAB &&
977 #ifdef sun
978 strcmp((char*)shstr_data->d_buf + shdr->sh_name, ".strtab") == 0 &&
979 #endif
980 cnt != ehdr->e_shstrndx) {
981 if (str_data != NULL) {
982 fprintf(stderr, "multiple string tables for %s - bailing\n",
983 EhObjectGetFilename(object, buf));
984 return -1;
986 str_data = elf_getdata(scn, NULL);
987 } else if (shdr->sh_type == SHT_SYMTAB) { /* look into sym table */
988 if (sym_data != NULL) {
989 fprintf(stderr, "multiple symbol tables for %s - bailing\n",
990 EhObjectGetFilename(object, buf));
991 return -1;
993 sym_data = elf_getdata(scn, NULL);
994 } else if (shdr->sh_type == SHT_REL) { /* look into rel table */
995 if (nrel_data >= 4) {
996 fprintf(stderr, "too many relocation tables for %s bailing\n",
997 EhObjectGetFilename(object, buf));
998 return -1;
1000 rel_data[nrel_data++] = elf_getdata(scn, NULL);
1001 } else if (shdr->sh_type == SHT_RELA) { /* look into rela table */
1002 if (nrela_data >= 10) {
1003 fprintf(stderr, "too many RELA tables for %s bailing\n",
1004 EhObjectGetFilename(object, buf));
1005 return -1;
1007 rela_data[nrela_data++] = elf_getdata(scn, NULL);
1011 if (sym_data == NULL) {
1012 fprintf(stderr, "could not load sym table for %s\n",
1013 EhObjectGetFilename(object, buf));
1014 return -1;
1017 if (str_data == NULL) {
1018 fprintf(stderr, "could not load string table for %s\n",
1019 EhObjectGetFilename(object, buf));
1020 return -1;
1023 elf_sym = (Elf32_Sym*)sym_data->d_buf;
1025 for (i = 0; i < (sym_data->d_size/sizeof(Elf32_Sym)); i++) {
1028 * We are only interested in globals.
1030 if (ELF32_ST_BIND(elf_sym[i].st_info) != STB_GLOBAL)
1031 continue;
1033 name = (char *)str_data->d_buf + elf_sym[i].st_name;
1035 if (djw_test_name != NULL
1036 && strcmp(djw_test_name, name) == 0) {
1037 printf("found %s\n", name);
1040 sym = EhSymTableFind(table, name);
1043 * Treat inlines as non-globals
1045 if (sym != NULL && sym->state == EH_SYM_INLINE)
1046 continue;
1048 #if 0
1049 printf("name = %s value = %d type = %d, info = %d,"
1050 " other = %d, size = %d\n",
1051 name,
1052 elf_sym[i].st_value,
1053 ELF32_ST_TYPE(elf_sym[i].st_info),
1054 elf_sym[i].st_info,
1055 elf_sym[i].st_other,
1056 elf_sym[i].st_size);
1057 #endif
1059 /* defined */
1060 if (ELFSYM_IS_DEFINED(elf_sym[i])) {
1062 if (sym != NULL) {
1064 if (sym->object == NULL) { /* object undefined */
1065 sym->object = object;
1066 } else if (sym->object->name==eh_unnamed_object) {
1068 if (object->source != NULL
1070 object->source != sym->object->source) {
1072 fprintf(stderr,
1073 "warning: symbol %s defined in more than one source file\n"
1074 "last time: %s\n"
1075 "this time: %s (ignored)\n",
1076 sym->name,
1077 object->source->name,
1078 sym->object->source->name);
1079 } else {
1080 object->source = sym->object->source;
1082 * Do a global: sym->object = object;
1084 EhSymTableObjectFixup(table,
1085 sym->object, /*old*/
1086 object); /*new*/
1090 } else if (sym->object != object) {
1091 fprintf(stderr,
1092 "warning: symbol %s define in multiple object files\n"
1093 "last time: %s\n"
1094 "this time: %s (ignored)\n",
1095 sym->name,
1096 object->name,
1097 sym->object->name);
1100 sym->state = EH_SYM_DEFINED;
1102 } else {
1103 sym = EhSymNewDefined(name, object);
1104 EhSymTableInsert(table, sym);
1107 for (k = 0; k < nrel_data; k++) {
1108 int nentries = rel_data[k]->d_size/sizeof(Elf32_Rel);
1110 rel_entries = (Elf32_Rel*)rel_data[k]->d_buf;
1112 for (j = 0; j < nentries; j++) {
1113 if (ELF32_R_SYM(rel_entries[j].r_info) == i) {
1114 /* locally referenced */
1115 sym->nlusers++;
1119 for (k = 0; k < nrela_data; k++) {
1120 int nentries = rela_data[k]->d_size/sizeof(Elf32_Rela);
1122 rela_entries = (Elf32_Rela*)rela_data[k]->d_buf;
1124 for (j = 0; j < nentries; j++) {
1125 if (ELF32_R_SYM(rela_entries[j].r_info) == i) {
1126 /* locally referenced */
1127 sym->nlusers++;
1133 /* Undefined. */
1134 else if (ELFSYM_IS_UNDEFINED(elf_sym[i])) {
1136 if (sym == NULL) {
1137 sym = EhSymNewUndefined(name);
1138 EhSymTableInsert(table, sym);
1140 sym->ngusers++;
1141 } else {
1143 #if 1
1144 printf("what is this: "
1145 "name = %s value = %d type = %d, "
1146 "info = %d, other = %d, size = %d\n",
1147 name,
1148 elf_sym[i].st_value,
1149 ELF32_ST_TYPE(elf_sym[i].st_info),
1150 elf_sym[i].st_info,
1151 elf_sym[i].st_other,
1152 elf_sym[i].st_size);
1153 #endif
1155 }/* type ==... */
1156 } /* for each symbol */
1158 return 0;
1162 eh_process_file(char* filename, EhSymTable* table, char* rootdir)
1164 Elf* elf;
1165 Elf* arf;
1166 int fd;
1167 Elf_Cmd cmd;
1168 Elf_Kind e_kind;
1169 EhObject* object;
1170 EhArchive* archive;
1171 Elf_Arhdr* arhdr;
1172 char* name;
1173 int rv = 0;
1175 if ((fd = open(filename, O_RDONLY)) == -1) {
1176 fprintf(stderr, "error opening %s\n", filename);
1177 return -1;
1180 elf_version(EV_CURRENT);
1181 if ((arf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
1182 return -1;
1185 e_kind = elf_kind(arf);
1186 if (e_kind == ELF_K_ELF) {
1187 object = EhObjectNew(filename, rootdir);
1188 rv = eh_process_object(arf, object, table);
1190 } else if (e_kind == ELF_K_AR) {
1192 archive = EhArchiveNew(filename, rootdir);
1193 cmd = ELF_C_READ;
1195 #if 0
1196 arsyms = elf_getarsym(arf, &narsyms);
1198 for (i = 0; i < narsyms && arsyms[i].as_name != NULL; i++) {
1199 printf("%s - %d\n", arsyms[i].as_name, arsyms[i].as_off);
1202 arhdr = elf_getarhdr(arf);
1203 for (i = 0; arhdr[i].ar_rawname != NULL; i++) {
1205 if (arhdr[i].ar_name != NULL)
1206 printf("%s\n", arhdr[i].ar_name);
1207 else
1208 printf("[%s]\n", arhdr[i].ar_rawname);
1210 #endif
1212 rv = 0;
1214 while ((elf = elf_begin(fd, cmd, arf)) != 0) {
1216 e_kind = elf_kind(elf);
1218 if (e_kind != ELF_K_ELF)
1219 continue;
1221 arhdr = elf_getarhdr(elf);
1223 if (arhdr != NULL) {
1224 if (arhdr->ar_name != NULL)
1225 name = arhdr->ar_name;
1226 else
1227 name = arhdr->ar_rawname;
1228 } else {
1229 name = eh_unnamed_object;
1232 object = EhObjectNewArchiveObject(archive, name);
1233 rv = eh_process_object(elf, object, table);
1235 if (rv == -1)
1236 break;
1238 cmd = elf_next(elf);
1239 elf_end(elf);
1243 elf_end(arf);
1245 close(fd);
1247 return rv;
1250 static int
1251 eh_dump_unused(EhSym* sym, void* arg)
1253 char buf[MAXPATHLEN];
1255 printf(/*"0x%x "*/ "%s %d %d ", /*sym,*/
1256 sym->name, sym->ngusers, sym->nlusers);
1258 if (EHSYM_ISINLINE(sym))
1259 printf("%c ", EH_TAG_INLINE);
1260 else if (EHSYM_ISZAPPED(sym))
1261 printf("%c ", EH_TAG_ZAPPED);
1262 else if (EHSYM_ISDEFINED(sym))
1263 printf("%c ", EH_TAG_GLOBAL);
1264 else
1265 printf("%c ", EH_TAG_UNDEFINED);
1267 if (sym->object != NULL) {
1268 printf("%s ", EhObjectGetFilename(sym->object, buf));
1269 if (sym->object->source != NULL) {
1270 printf("%s recompilable\n", sym->object->source->name);
1271 } else {
1272 printf("nosource notrecompilable\n");
1274 } else {
1275 printf("noobject nosource notrecompilable\n");
1278 return 0;
1281 static void
1282 print_dump(EhSymTable* table)
1284 printf("everything\n");
1285 EhSymTableMap(table, eh_dump_unused, NULL);
1288 typedef struct {
1289 unsigned ndefined;
1290 unsigned nused; /* globally */
1291 unsigned nundefined;
1292 unsigned nzapped;
1293 unsigned nzapped_nowused;
1294 unsigned ninlined;
1295 unsigned nunlinked;
1296 unsigned ndeadcode;
1297 } SummaryInfo;
1299 static int
1300 eh_summary_mappee(EhSym* sym, void* arg) {
1301 SummaryInfo* info = (SummaryInfo*)arg;
1303 if (EHSYM_ISDEFINED(sym)) {
1304 if (sym->ngusers != 0)
1305 info->nused++;
1306 else if (sym->object != NULL && sym->object->nusers == 0)
1307 info->nunlinked++;
1308 else if (sym->nlusers != 0)
1309 info->ndefined++;
1310 else
1311 info->ndeadcode++;
1313 } else if (EHSYM_ISZAPPED(sym)) { /* one of ours */
1314 if (sym->ngusers != 0)
1315 info->nzapped_nowused++;
1316 else
1317 info->nzapped++;
1318 } else if (EHSYM_ISINLINE(sym)) { /* one of ours */
1319 info->ninlined++;
1320 } else {
1321 info->nundefined++;
1324 return 0;
1327 static void
1328 get_summary(EhSymTable* table, SummaryInfo* info)
1330 info->ndefined = 0;
1331 info->nused = 0;
1332 info->nundefined = 0;
1333 info->nzapped = 0;
1334 info->nzapped_nowused = 0;
1335 info->ninlined = 0;
1336 info->nunlinked = 0;
1337 info->ndeadcode = 0;
1339 EhSymTableMap(table, eh_summary_mappee, info);
1342 static void
1343 print_summary(EhSymTable* table)
1345 SummaryInfo info;
1347 get_summary(table, &info);
1349 printf("summary:\n"
1350 "defined and used: %d\n"
1351 "defined but unused globally: %d\n"
1352 "total globals in target: %d\n"
1353 "--------------------------------\n"
1354 "global to statics *: %d\n"
1355 "global to statics (now used): %d\n"
1356 "inlined to statics *: %d\n"
1357 "defined in unlinked objects: %d\n"
1358 "defined but unused (deadcode):%d\n"
1359 "undefined but used: %d\n",
1360 info.nused,
1361 info.ndefined,
1362 (info.nused + info.ndefined),
1363 info.nzapped,
1364 info.nzapped_nowused,
1365 info.ninlined,
1366 info.nunlinked,
1367 info.ndeadcode,
1368 info.nundefined);
1371 typedef struct EhDirMapEntree {
1372 char* dirname;
1373 struct EhDirMapEntree* _next;
1374 } EhDirMapEntree;
1376 typedef struct EhDirMap {
1377 EhDirMapEntree* head;
1378 } EhDirMap;
1380 static EhDirMap*
1381 EhDirMapNew(void)
1383 EhDirMap* dm = EH_NEW(EhDirMap);
1384 dm->head = NULL;
1385 return dm;
1388 static void
1389 EhDirMapAddDirectory(EhDirMap* map, char* dirname)
1391 EhDirMapEntree* entree = EH_NEW(EhDirMapEntree);
1392 EhDirMapEntree* foo;
1394 entree->dirname = strdup(dirname);
1395 entree->_next = NULL;
1397 if (map->head == NULL) {
1398 map->head = entree;
1399 } else {
1400 for (foo = map->head; foo->_next != NULL; foo = foo->_next)
1403 foo->_next = entree;
1407 static char*
1408 EhDirMapGetLibName(EhDirMap* map, char* name, char* libbuf)
1410 EhDirMapEntree* foo;
1411 struct stat buf;
1413 for (foo = map->head; foo != NULL; foo = foo->_next) {
1414 sprintf(libbuf, "%s/lib%s.a", foo->dirname, name);
1416 if (stat(libbuf, &buf) != -1)
1417 return libbuf;
1420 return NULL;
1423 static char*
1424 test_for_global(char* buf)
1426 #ifdef IRIX
1427 if (strncmp(buf, "\t.globl\t", 8) == 0)
1428 return &buf[8];
1429 #else
1430 if (strncmp(buf, "\t.global ", 9) == 0)
1431 return &buf[9];
1432 #endif
1433 return NULL;
1436 static char*
1437 test_for_file(char* foo, char* buf)
1439 #ifdef IRIX
1440 char* p;
1441 char* q;
1442 if (strncmp(buf, "\t.file\t", 6) == 0) {
1443 for (p = &buf[6]; *p != '"' && *p != '\0'; p++)
1445 if (*p == '\0')
1446 return NULL;
1447 p++; /* quote */
1448 q = strchr(p, '"');
1449 if (q == NULL)
1450 return NULL;
1451 memcpy(foo, p, q - p);
1452 foo[q - p] = '\0';
1453 return foo;
1455 #else
1456 printf("test_for_file() not implemented\n");
1457 #endif
1458 return NULL;
1461 static int
1462 EhSourceZapFp(EhSource* source, EhSymTable* table, FILE* fpi, FILE* fpo,
1463 unsigned verbosity, unsigned cplusplus)
1465 char* buf = NULL;
1466 char* p;
1467 int nzap = 0;
1468 char* name;
1469 EhSym* sym;
1470 int i_zapped;
1471 EhObject* object = EhObjectNewFromSource(source);
1472 char* filename = source->name;
1473 char* tmp_name;
1474 char foo[256];
1475 unsigned line_n = 0;
1477 if (VERBOSITY_DEBUG(verbosity))
1478 fputs("gts: ", stderr);
1480 while ((buf = safe_fgets(buf, 4192, fpi)) != NULL) {
1482 i_zapped = 0;
1483 for (p = buf; *p != '\0' && *p != '\n'; p++)
1485 *p = '\0';
1487 if ((tmp_name = test_for_file(foo, buf)) != NULL) {
1488 if (strcmp(tmp_name, filename) != 0) /* not the same file */
1489 filename = "non local file";
1490 else
1491 filename = source->name;
1494 else if ((name = test_for_global(buf)) != NULL) {
1496 sym = EhSymTableFind(table, name);
1498 /* an inline, we have to treat specially */
1499 if ((filename != source->name && cplusplus != 0) /* inline now */
1501 (sym != NULL && sym->state == EH_SYM_INLINE)) {/* was inline */
1503 if (!sym) {
1505 sym = EhSymNewInline(name);
1507 EhSymTableInsert(table, sym);
1509 sym->state = EH_SYM_INLINE; /* just make sure */
1511 if (fpo != NULL) /* always zap inlines we see */
1512 fputs(" # gts", fpo);
1514 } else { /* a real global */
1516 if (fpo != NULL && sym != NULL && EHSYM_ISZAPPED(sym)) {
1517 if (VERBOSITY_DEBUG(verbosity)) {
1518 fprintf(stderr, "%s ", &buf[8]);
1520 nzap++;
1522 if (fpo != NULL)
1523 fputs(" # gts", fpo);
1526 if (sym != NULL) {
1527 if (sym->object == NULL) {
1528 sym->object = object;
1529 } else if (sym->object != object) {
1530 sym->object->source = source;
1531 EhSymTableObjectFixup(table, object, sym->object);
1532 object = sym->object;
1534 } else { /* install a new one */
1536 sym = EhSymNewDefined(name, object);
1538 EhSymTableInsert(table, sym);
1544 if (fpo != NULL) {
1545 fputs(buf, fpo);
1546 fputc('\n', fpo);
1548 line_n++;
1551 if (VERBOSITY_DEBUG(verbosity))
1552 fputc('\n', stderr);
1554 return nzap;
1557 static void
1558 print_command(char* command, char** args, unsigned verbosity)
1560 int i;
1561 FILE* fp = stderr;
1562 if (!VERBOSITY_USER(verbosity))
1563 return;
1565 fprintf(fp, "%s: ", command);
1566 for (i = 0; args[i]; i++) {
1567 fprintf(fp, "%s ", args[i]);
1569 fprintf(fp, "\n");
1572 static int
1573 do_command(char* label, char** args, unsigned verbosity)
1575 int status;
1576 pid_t child_pid;
1577 char* file = args[0];
1579 print_command(label, args, verbosity);
1581 if ((child_pid = fork()) == -1) {
1582 fprintf(stderr, "could not fork: ");
1583 perror(NULL);
1584 return -1;
1587 if (child_pid == 0) { /* i am the child */
1588 if (execvp(file, args) == -1) {
1589 fprintf(stderr, "could not exec %s: ", file);
1590 perror(NULL);
1591 exit(3);
1593 /*NOTREACHED*/
1596 if (waitpid(child_pid, &status, 0) == -1) {
1597 fprintf(stderr, "wait on %s failed: ", file);
1598 perror(NULL);
1599 return -1;
1602 return WEXITSTATUS(status);
1605 static char*
1606 suffix_name(char* s)
1608 char* p;
1610 if ((p = strrchr(s, '.')) != NULL)
1611 return p;
1612 else
1613 return "";
1616 static char base_name_buf[MAXPATHLEN];
1618 static char*
1619 base_name(char* s)
1621 char* p;
1623 if ((p = strrchr(s, '.')) != NULL) {
1624 memcpy(base_name_buf, s, p - s);
1625 base_name_buf[p - s] = '\0';
1626 s = base_name_buf;
1628 return s;
1631 static char*
1632 file_base_name(char *s)
1634 char* p;
1636 s = base_name(s);
1638 if ((p = strrchr(s, '/')) != NULL)
1639 s = &p[1];
1641 return s;
1643 static int
1644 EhSourceCompile(EhSource* source,
1645 EhSymTable* table,
1646 unsigned verbosity,
1647 unsigned do_compile,
1648 unsigned do_zap,
1649 unsigned do_assem)
1651 char* filename = source->name;
1652 char** opts = source->cc_args;
1653 char asname[MAXPATHLEN];
1654 char o_asname[MAXPATHLEN];
1655 char* cc_opts[256];
1656 unsigned i = 0;
1657 unsigned j = 0;
1658 FILE* in_fp;
1659 FILE* out_fp;
1660 int status;
1661 int nzap = 0;
1662 char* save_prefix = NULL;
1663 unsigned do_dash_s = (do_zap != 0 || save_prefix != NULL);
1664 char* cc_command;
1665 char* use_savefile = NULL;
1666 struct timeval start_time;
1667 struct timeval end_time;
1668 #ifdef DEBUG_djw
1669 char savebuf[1024];
1670 #endif
1671 unsigned is_cplusplus = 0;
1673 #ifdef LINUX
1674 gettimeofday(&start_time,NULL);
1675 #else
1676 gettimeofday(&start_time);
1677 #endif
1679 /* munge file */
1680 #ifdef HANDLES_DASHSO
1681 if (source->target_object != NULL)
1682 strcpy(asname, base_name(source->target_object));
1683 else
1684 #endif
1685 strcpy(asname, file_base_name(filename));
1686 strcat(asname, ".s");
1688 strcpy(o_asname, asname);
1689 strcat(o_asname, ".gts_tmp");
1691 if (strcmp(suffix_name(filename), ".cpp") == 0) {
1692 cc_command = CCC_COMMAND;
1693 is_cplusplus = 1;
1694 } else if (strcmp(suffix_name(filename), ".s") == 0) {
1695 do_compile = FALSE;
1696 cc_command = CC_COMMAND;
1697 } else {
1698 cc_command = CC_COMMAND;
1701 if (do_compile) {
1703 j = 0;
1704 cc_opts[j++] = cc_command;
1705 cc_opts[j++] = "-c";
1707 if (do_dash_s) {
1708 cc_opts[j++] = "-S";
1709 #ifdef HANDLES_DASHSO
1710 if (source->target_object != NULL) {
1711 cc_opts[j++] = "-o";
1712 cc_opts[j++] = asname;
1714 #endif
1715 } else if (source->target_object != NULL) {
1716 cc_opts[j++] = "-o";
1717 cc_opts[j++] = source->target_object;
1720 i = 0;
1721 while (opts[i] != NULL)
1722 cc_opts[j++] = opts[i++];
1724 cc_opts[j++] = filename;
1725 cc_opts[j] = NULL;
1727 if ((status = do_command("compile", cc_opts, verbosity)) != 0) {
1728 fprintf(stderr, "compile failed (returned %d)\n", status);
1729 return -1;
1732 if (!do_dash_s)
1733 return 0;
1737 * Now we have a foo.s file, what do we do with it?
1739 if (do_zap > 1) {
1741 if (use_savefile == NULL)
1742 use_savefile = asname;
1744 if ((in_fp = fopen(use_savefile, "r")) == NULL) {
1745 fprintf(stderr, "could not open %s for reading\n", asname);
1746 return -1;
1749 if ((out_fp = fopen(o_asname, "w")) == NULL) {
1750 fprintf(stderr, "could not open %s for writing\n", o_asname);
1751 return -1;
1754 j = 0;
1755 cc_opts[j++] = "gts";
1756 cc_opts[j++] = asname;
1757 cc_opts[j++] = o_asname;
1758 cc_opts[j++] = NULL;
1759 print_command("gts", cc_opts, verbosity);
1761 nzap = EhSourceZapFp(source, table, in_fp, out_fp, verbosity, is_cplusplus);
1763 fclose(in_fp);
1764 fclose(out_fp);
1766 j = 0;
1767 cc_opts[j++] = "rename";
1768 cc_opts[j++] = o_asname;
1769 cc_opts[j++] = asname;
1770 cc_opts[j++] = NULL;
1771 print_command("rename", cc_opts, verbosity);
1773 #ifdef DEBUG_djw
1774 strcpy(savebuf, "gts_pre_");
1775 strcat(savebuf, asname);
1776 rename(asname, savebuf);
1777 #endif
1779 if (rename(o_asname, asname) == -1) {
1780 fprintf(stderr, "could not rename %s\n", o_asname);
1781 return -1;
1784 } else if (do_zap > 0) { /* audit only */
1786 if ((in_fp = fopen(asname, "r")) == NULL) {
1787 fprintf(stderr, "could not open %s for reading\n", asname);
1788 return -1;
1791 j = 0;
1792 cc_opts[j++] = "audit";
1793 cc_opts[j++] = asname;
1794 cc_opts[j++] = NULL;
1795 print_command("audit", cc_opts, verbosity);
1797 nzap = EhSourceZapFp(source, table, in_fp, NULL, verbosity, is_cplusplus);
1799 fclose(in_fp);
1802 if (do_assem) {
1803 i = 0;
1804 j = 0;
1805 cc_opts[j++] = AS_COMMAND;
1806 cc_opts[j++] = "-c";
1808 if (source->target_object != NULL) {
1809 cc_opts[j++] = "-o";
1810 cc_opts[j++] = source->target_object;
1813 while (opts[i] != NULL)
1814 cc_opts[j++] = opts[i++];
1816 cc_opts[j++] = asname;
1817 cc_opts[j] = NULL;
1819 if ((status = do_command("assemble", cc_opts, verbosity)) != 0) {
1821 unlink(asname);
1823 fprintf(stderr,
1824 "gtscc of %s failed (exit status = %d), reverting to %s:\n",
1825 filename,
1826 status,
1827 cc_command);
1829 i = 0;
1830 j = 0;
1831 cc_opts[j++] = cc_command;
1832 cc_opts[j++] = "-c";
1834 if (source->target_object != NULL) {
1835 cc_opts[j++] = "-o";
1836 cc_opts[j++] = source->target_object;
1839 for (; opts[i]; i++, j++)
1840 cc_opts[j] = opts[i];
1842 cc_opts[j++] = filename;
1843 cc_opts[j] = NULL;
1845 if ((status = do_command("fix-compile", cc_opts, verbosity)) != 0)
1846 return -1;
1848 return 0;
1852 if (save_prefix != NULL && save_prefix[0] != '\0') {
1854 sprintf(o_asname, save_prefix, file_base_name(filename));
1856 j = 0;
1857 cc_opts[j++] = "rename";
1858 cc_opts[j++] = asname;
1859 cc_opts[j++] = o_asname;
1860 cc_opts[j++] = NULL;
1861 print_command("savefile", cc_opts, verbosity);
1863 if (rename(asname, o_asname) == -1) {
1864 fprintf(stderr, "could not rename %s to %s - sorry\n",
1865 asname, o_asname);
1866 return -1;
1869 if (source->as_savefile != NULL)
1870 free(source->as_savefile);
1871 source->as_savefile = strdup(o_asname);
1872 } else {
1874 j = 0;
1875 cc_opts[j++] = "unlink";
1876 cc_opts[j++] = asname;
1877 cc_opts[j++] = NULL;
1878 print_command("unlink", cc_opts, verbosity);
1880 #ifdef DEBUG_djw
1881 strcpy(savebuf, "gts_post_");
1882 strcat(savebuf, asname);
1883 rename(asname, savebuf);
1884 #else
1885 unlink(asname);
1886 #endif
1889 #ifdef LINUX
1890 gettimeofday(&end_time,NULL);
1891 #else
1892 gettimeofday(&end_time);
1893 #endif
1895 source->compile_time = ((end_time.tv_sec - start_time.tv_sec) * 1000) +
1896 ((end_time.tv_usec - start_time.tv_usec) / 1000);
1898 return nzap;
1901 static char target_buf[MAXPATHLEN]; /* this will go away with rel source */
1903 static char*
1904 EhSourceGetTarget(EhSource* source)
1906 if (source->target_object != NULL)
1907 return source->target_object;
1909 strcpy(target_buf, base_name(source->name));
1910 strcat(target_buf, ".o");
1912 return target_buf;
1915 static int
1916 EhArchiveUpdate(EhArchive* archive, char* target, char* rootdir,
1917 unsigned verbosity)
1919 char* args[8];
1920 unsigned nargs;
1921 int status;
1922 char pathname[MAXPATHLEN];
1924 pathname[0] = '\0';
1925 if (rootdir != NULL) {
1926 strcat(pathname, rootdir);
1927 strcat(pathname, "/");
1929 strcat(pathname, archive->name);
1931 #if 0
1932 nargs = 0;
1933 args[nargs++] = AR_COMMAND;
1934 args[nargs++] = "dc";
1935 args[nargs++] = pathname;
1936 args[nargs++] = target;
1937 args[nargs++] = NULL;
1939 if ((status = do_command("delete from archive", args, verbosity)) != 0) {
1940 fprintf(stderr, "archive: %s delete %s failed (status = %d)\n",
1941 pathname,
1942 target);
1943 return -1;
1945 #endif
1947 nargs = 0;
1948 args[nargs++] = AR_COMMAND;
1949 args[nargs++] = AR_OPTIONS;
1950 args[nargs++] = pathname;
1951 args[nargs++] = target;
1952 args[nargs++] = NULL;
1954 if ((status = do_command("archive", args, verbosity)) != 0) {
1955 fprintf(stderr, "archive: %s <- %s failed (status = %d)\n",
1956 pathname,
1957 target);
1958 return -1;
1961 return 0;
1964 static int
1965 EhObjectRebuild(EhObject* object,
1966 EhSymTable* table,
1967 unsigned verbosity,
1968 char* rootdir)
1970 EhSource* source = object->source;
1971 char cwd[MAXPATHLEN];
1972 char fullpath[MAXPATHLEN];
1973 int rv = 0;
1974 int do_chdir = 0;
1976 if (!source) {
1977 fprintf(stderr,
1978 "wanted to recompile %s, but I don't how\n",
1979 object->name);
1980 return -1;
1983 #if 0
1984 if (VERBOSITY_USER(verbosity))
1985 #endif
1986 fprintf(stderr, "recompiling %s\n", source->name);
1989 * Check to see if we need to chdir
1991 if (source->directory != NULL) {
1992 if (getcwd(cwd, sizeof(cwd)) == NULL) {
1993 fprintf(stderr, "cannot get pwd: cannot compile\n");
1994 return -1;
1997 make_relative_pathname(fullpath, cwd, rootdir);
1999 if (strcmp(fullpath, source->directory) != 0) {
2000 fullpath[0] = '\0';
2001 if (rootdir != NULL) {
2002 strcat(fullpath, rootdir);
2003 strcat(fullpath, "/");
2005 strcat(fullpath, source->directory);
2007 if (chdir(fullpath) == -1) {
2008 fprintf(stderr, "cannot chdir - can't compile\n");
2009 return -1;
2011 do_chdir++;
2015 rv = EhSourceCompile(source,
2016 table,
2017 verbosity,
2018 TRUE, /* compile */
2019 2, /* do zap */
2020 TRUE); /* do assem */
2022 if (do_chdir) {
2023 if (chdir(cwd) == -1) {
2024 fprintf(stderr, "cannot chdir - this will be very confused\n");
2025 return -1;
2029 if (rv == -1) {
2030 fprintf(stderr, "recompiling %s failed\n", source->name);
2031 return -1;
2034 /* do archive */
2035 fullpath[0] = '\0';
2036 if (rootdir != NULL) {
2037 strcat(fullpath, rootdir);
2038 strcat(fullpath, "/");
2041 if (source->directory != NULL)
2042 strcat(fullpath, source->directory);
2044 strcat(fullpath, "/");
2045 strcat(fullpath, EhSourceGetTarget(source));
2047 if (object->archive != NULL) {
2048 if (EhArchiveUpdate(object->archive, fullpath, rootdir,
2049 verbosity) == -1)
2050 return -1;
2053 /* do install */
2054 #if 0
2055 if (rv != -1) {
2057 #endif
2059 return rv;
2062 static int
2063 object_nusers_mappee(EhSym* sym, void* arg)
2065 if (sym->object != NULL)
2066 sym->object->nusers += sym->ngusers;
2067 return 0;
2070 typedef struct {
2071 EhObject* recompile_list;
2072 unsigned recompile_count;
2073 unsigned recompile_wish_count;
2074 unsigned unzap_count;
2075 unsigned zap_count;
2076 } RecompileInfo;
2078 static int
2079 recompile_init_mappee(EhSym* sym, void* arg)
2081 RecompileInfo* info = (RecompileInfo*)arg;
2083 if (EHSYM_ISZAPPED(sym) && sym->ngusers != 0) {
2084 if (EH_OBJECT_CANBUILD(sym->object)) {
2085 sym->state = EH_SYM_DEFINED;
2086 if (sym->object->_recompile == NULL) {
2087 sym->object->_recompile = info->recompile_list;
2088 info->recompile_list = sym->object;
2089 info->recompile_count++;
2091 info->unzap_count++;
2092 sym->object->_needs_unzap++;
2094 info->recompile_wish_count++;
2096 else if (EHSYM_ISDEFINED(sym) /* it's defined */
2097 && sym->ngusers == 0 /* there are no global users */
2098 && sym->nlusers != 0 /* BUT, ther are local users */
2099 && sym->object->nusers != 0) { /* object is linked */
2101 if (EH_OBJECT_CANBUILD(sym->object)) {
2102 sym->state = EH_SYM_ZAPPED;
2103 if (sym->object->_recompile == NULL) {
2104 sym->object->_recompile = info->recompile_list;
2105 info->recompile_list = sym->object;
2106 info->recompile_count++;
2108 info->zap_count++;
2110 info->recompile_wish_count++;
2113 return 0;
2116 static char** recompile_compare_prefs;
2117 static char** recompile_compare_unprefs;
2119 static unsigned
2120 match_prefs(char* candidate, char** prefs)
2122 unsigned n;
2124 for (n = 0; prefs[n] != NULL; n++) {
2125 char* pref = prefs[n];
2126 unsigned len = strlen(pref);
2127 if (strncmp(pref, candidate, len) == 0)
2128 return n; /* cool */
2130 return (unsigned)-1; /* big! */
2133 static int
2134 recompile_compare(const void* ap, const void* bp)
2136 EhObject** ax = (EhObject**)ap;
2137 EhObject** bx = (EhObject**)bp;
2138 EhObject* obj_a = *ax;
2139 EhObject* obj_b = *bx;
2140 EhSource* src_a = obj_a->source;
2141 EhSource* src_b = obj_b->source;
2142 unsigned matcha;
2143 unsigned matchb;
2144 int foo;
2146 if (obj_a->_needs_unzap == 0 && obj_b->_needs_unzap != 0)
2147 return -1;
2148 if (obj_a->_needs_unzap != 0 && obj_b->_needs_unzap == 0)
2149 return 1;
2151 if (src_a == NULL && src_b != NULL)
2152 return 1;
2153 if (src_a != NULL && src_b == NULL)
2154 return -1;
2155 if (src_a == src_b)
2156 return 0;
2158 if (recompile_compare_unprefs != NULL
2159 && src_a->directory != NULL && src_b->directory != NULL) {
2161 matcha = match_prefs(src_a->directory, recompile_compare_unprefs);
2162 matchb = match_prefs(src_b->directory, recompile_compare_unprefs);
2164 if (matcha > matchb) /* greater is good */
2165 return -1;
2166 if (matcha < matchb)
2167 return 1;
2170 if (recompile_compare_prefs != NULL
2171 && src_a->directory != NULL && src_b->directory != NULL) {
2173 matcha = match_prefs(src_a->directory, recompile_compare_prefs);
2174 matchb = match_prefs(src_b->directory, recompile_compare_prefs);
2176 if (matcha > matchb) /* greater is bad */
2177 return 1;
2178 if (matcha < matchb)
2179 return -1;
2182 /* else same directory probably */
2183 foo = strcmp(src_a->name, src_b->name);
2185 if (foo < 0)
2186 return -1;
2187 if (foo > 0)
2188 return 1;
2190 return 0;
2193 static int
2194 do_recompilation(EhSymTable* table, char* gts_file, unsigned max_globals,
2195 char** prefs, char** unprefs,
2196 char* rootdir, unsigned verbosity)
2198 SummaryInfo s_info;
2199 RecompileInfo info;
2200 unsigned size;
2201 unsigned n;
2202 EhObject* object;
2203 EhObject** recompiles;
2204 unsigned delta;
2205 int rv;
2206 unsigned nzaps;
2207 EhObject dummy; /* just marks the end of the recomp list */
2208 time_t eta;
2210 get_summary(table, &s_info);
2212 if ((s_info.nused + s_info.ndefined) <= max_globals) {
2213 if (VERBOSITY_USER(verbosity))
2214 fprintf(stderr,
2215 "number of globals <= requested max, skipping recompilation\n");
2216 return 0;
2219 /* Init recompilation. */
2220 info.recompile_list = &dummy; /* cannot use NULL, because syms test that */
2221 info.recompile_count = 0;
2222 info.recompile_wish_count = 0;
2223 info.unzap_count = 0;
2224 info.zap_count = 0;
2225 EhSymTableMap(table, recompile_init_mappee, (void*)&info);
2226 size = info.recompile_count;
2228 recompiles = (EhObject**)malloc(sizeof(EhObject*) * size);
2230 /* install */
2231 n = 0;
2232 for (object = info.recompile_list;
2233 object != &dummy;
2234 object = object->_recompile) {
2235 recompiles[n++] = object;
2238 /* sort */
2239 recompile_compare_prefs = prefs;
2240 recompile_compare_unprefs = unprefs;
2241 qsort(recompiles, size, sizeof(EhObject*), recompile_compare);
2244 * sorted !
2245 * less recompile the first n, n = ndefined - max
2247 delta = (s_info.nused + s_info.ndefined) - max_globals;
2249 if (delta > info.zap_count) {
2250 fprintf(stderr,
2251 "WARNING: there too many globals (%d/%d fixables).\n"
2252 " I don't think I can fix this, but I'll try.\n"
2253 " You might get lucky.\n",
2254 info.zap_count,
2255 delta);
2258 if (VERBOSITY_USER(verbosity))
2259 fprintf(stderr, "scheduling recompilation targets:\n");
2261 eta = 0;
2262 for (n = 0; n < size; n++) {
2263 char* cname = "unknown";
2264 object = recompiles[n];
2265 if (object->source != NULL) {
2266 cname = object->source->name;
2267 eta += object->source->compile_time;
2270 if (VERBOSITY_DEBUG(verbosity))
2271 fprintf(stderr, "object %s from source %s\n", object->name, cname);
2274 #if 0
2275 if (VERBOSITY_USER(verbosity))
2276 #endif
2277 fprintf(stderr, "gts-ing %d symbols, eta = %d minutes\n", delta,
2278 eta/(60*1000));
2280 if (gts_file != NULL) {
2281 FILE* zap_fp;
2282 if ((zap_fp = fopen(gts_file, "w")) == NULL) {
2283 perror(0);
2284 fprintf(stderr,
2285 "WARNING: could not open the gtscc db file %s.\n"
2286 " I will continue with the recompilation, but\n"
2287 " if you recompile any of the files I touched\n"
2288 " I'll have to recompile them after you!\n",
2289 gts_file);
2290 } else {
2292 EhSymTableFpDump(table, zap_fp);
2294 fclose(zap_fp);
2298 for (n = 0, nzaps = 0; n < size && nzaps < delta; n++) {
2300 object = recompiles[n];
2301 rv = EhObjectRebuild(object, table, verbosity, rootdir);
2303 if (rv == -1)
2304 return -1;
2306 nzaps += rv;
2308 object->_recompile = NULL; /* clean up now */
2311 if (nzaps < delta) {
2312 fprintf(stderr,
2313 "WARNING: I wanted to gts %d symbols, but only managed\n"
2314 " to get %d of them.\n"
2315 " Your link may fail with GOT errors.\n",
2316 delta,
2317 nzaps);
2320 free(recompiles);
2322 return n;
2325 typedef struct FileList
2327 char* name;
2328 struct FileList* next;
2329 } FileList;
2331 static FileList*
2332 fileListFind(FileList* list, char* name)
2334 FileList* foo;
2336 for (foo = list; foo != NULL; foo = foo->next) {
2337 if (strcmp(name, foo->name) == 0)
2338 return foo;
2340 return NULL;
2343 static FileList*
2344 fileListAppend(FileList** list_a, char* name)
2346 FileList* list = *list_a;
2347 FileList* foo;
2348 FileList* last;
2350 for (foo = list, last = NULL; foo != NULL; last = foo, foo = foo->next)
2353 if (last == NULL) {
2354 foo = EH_NEW(FileList);
2355 foo->next = NULL;
2356 foo->name = strdup(name);
2357 *list_a = foo;
2358 } else {
2359 foo = EH_NEW(FileList);
2360 foo->next = NULL;
2361 foo->name = strdup(name);
2362 last->next = foo;
2365 return *list_a;
2368 #if 0
2369 static FileList* c_list;
2370 #endif
2371 static FileList* o_list;
2373 #if 0
2374 static char*
2375 EhSourceAdjustPathname(EhSource* source, char* rootdir)
2377 char buf[MAXPATHLEN];
2378 char buf2[MAXPATHLEN];
2379 char* p;
2380 char* q;
2381 char* filename = source->name;
2383 if (getcwd(buf, sizeof(buf)) == NULL) {
2384 fprintf(stderr, "cannot get pwd\n");
2385 return NULL;
2388 strcat(buf, "/");
2389 strcat(buf, filename);
2391 if (rootdir == NULL) {
2392 filename = buf;
2393 } else {
2394 if (realpath(buf, buf2) == NULL) {
2395 fprintf(stderr, "realpath() failed: %s\n", buf2);
2396 return NULL;
2399 if (realpath(rootdir, buf) == NULL) {
2400 fprintf(stderr, "realpath() failed: %s\n", buf);
2401 return NULL;
2403 strcat(buf, "/");
2405 for (p = buf, q = buf2; *p == *q; p++, q++)
2408 filename = q;
2411 free(source->name);
2412 source->name = strdup(filename);
2414 return source->name;
2416 #endif
2418 static unsigned
2419 katoi(char *buf)
2421 unsigned base = 1;
2422 char* s;
2424 for (s = buf; isdigit(*s); s++)
2427 if (*s == 'k' || *s == 'K')
2428 base = 1024;
2430 *s = '\0';
2432 return base * atoi(buf);
2435 static void
2436 usage(void)
2438 fprintf(stderr,
2439 "Usage:\n"
2440 "as a compiler:\n"
2441 "gtscc [gtscc_options] [compiler_options] -c file.c file.cpp ...\n"
2442 "gtscc_options:\n"
2443 "-gtsfile <db.gts> the gts database file (use this)\n"
2444 "-gtszapsymbol <name> convert symbol <name>\n"
2445 "-gtsnozapsymbol <name> don't convert symbol <name>\n"
2446 "-gtsrootdir <directory> the root for the tree (use this)\n"
2447 "-gtsverbose be more verbose (3 levels)\n"
2448 "-gtsnozap don't convert globals to statics\n"
2449 "-gtsnoupdate don't update the database file\n"
2450 "as a linker:\n"
2451 "gtscc [gtscc_options] [linker_options] file.o ... libxx.a ...\n"
2452 "gtscc_options:\n"
2453 "-gtsfile <db.gts> the gts database file (use this)\n"
2454 "-gtszapsymbol <name> convert symbol <name>\n"
2455 "-gtsnozapsymbol <name> don't convert symbol <name>\n"
2456 "-gtsrootdir <directory> the root for the tree (use this)\n"
2457 "-gtspref <directory> please recompile these paths first\n"
2458 "-gtsunpref <directory> please try to avoid recompiling these\n"
2459 "-gtsverbose be more verbose (3 levels)\n"
2460 "-gtssummary print a summary of global usage\n"
2461 "-gtsdump print a detailed listing of all symbols\n"
2462 "-gtsmaxglobals <number>[k] maximum globals allowed in target\n"
2463 "-gtsnorecompile don't do the normal recompilation\n"
2464 "-gtsnolink don't call linker after recompilation\n"
2465 "-gtsnoupdate don't update the database file\n"
2466 "-help print this\n"
2471 main(int argc, char** argv)
2473 EhSymTable* table = EhSymTableNew(1000);
2474 EhSym* sym;
2475 FILE* zap_fp;
2476 unsigned n = 0;
2477 unsigned verbosity = 0;
2478 char* arg_buf[256];
2479 unsigned nargs = 0;
2480 EhDirMap* dmap = EhDirMapNew();
2481 unsigned do_dump = 0;
2482 unsigned do_summary = 0;
2483 unsigned do_link = 1;
2484 unsigned in_link = 1;
2485 unsigned do_audit = 1;
2486 unsigned do_zap = 1;
2487 unsigned do_assem = 1;
2488 unsigned do_recompile = 1;
2489 unsigned do_collect = 1;
2490 char* name;
2491 char* saveprefix = NULL;
2492 char* rootdir = NULL;
2493 int rv;
2494 EhSource* source = NULL;
2495 char* gts_file = NULL;
2496 char* path_prefs[32];
2497 unsigned npath_prefs = 0;
2498 char* path_un_prefs[32];
2499 unsigned npath_un_prefs = 0;
2500 char* suffix;
2501 unsigned max_globals = DEFAULT_MAX_GLOBALS;
2502 FileList* list;
2504 if (elf_version(EV_CURRENT) == EV_NONE) {
2505 fprintf(stderr, "something losing about your elf lib - sorry!\n");
2506 return 3;
2507 /* library out of date */
2508 /* recover from error */
2511 arg_buf[nargs] = NULL;
2513 for (n = 1; n < argc; n++) {
2515 if (strcmp(argv[n], "-help") == 0) {
2516 usage();
2517 return 0;
2518 } else if (strcmp(argv[n], "-gtssummary") == 0) {
2519 do_summary = 1;
2520 } else if (strcmp(argv[n], "-gtsdump") == 0) {
2521 do_dump = 1;
2522 } else if (strcmp(argv[n], "-gtsnorecompile") == 0) {
2523 do_recompile = 0;
2524 } else if (strcmp(argv[n], "-gtsnolink") == 0) {
2525 do_link = 0;
2526 } else if (strcmp(argv[n], "-gtsverbose") == 0) {
2527 verbosity++;
2528 } else if (strcmp(argv[n], "-gtsnoupdate") == 0) {
2529 do_collect = 0;
2530 } else if (strcmp(argv[n], "-gtsnoaudit") == 0) {
2531 do_audit = 0;
2532 } else if (strcmp(argv[n], "-gtsnozap") == 0) {
2533 do_zap = 0;
2534 } else if (strcmp(argv[n], "-gtsrootdir") == 0) {
2535 if (argc < n+2) {
2536 fprintf(stderr, "-gtsrootdir requires an argument\n");
2537 usage();
2538 return 2;
2540 rootdir = argv[n+1];
2541 n++;
2542 } else if (strcmp(argv[n], "-gtsdebugsym") == 0) {
2543 if (argc < n+2) {
2544 fprintf(stderr, "-gtsdebugsym requires an argument\n");
2545 usage();
2546 return 2;
2548 djw_test_name = argv[n+1];
2549 n++;
2550 } else if (strcmp(argv[n], "-gtsmaxglobals") == 0) {
2551 if (argc < n+2) {
2552 fprintf(stderr, "-gtsmaxglobals requires an argument\n");
2553 usage();
2554 return 2;
2556 max_globals = katoi(argv[n+1]);
2557 n++;
2559 } else if (strcmp(argv[n], "-gtspref") == 0) {
2560 if (argc < n+2) {
2561 fprintf(stderr, "-gtspref requires an argument\n");
2562 usage();
2563 return 2;
2565 path_prefs[npath_prefs++] = argv[n+1];
2566 path_prefs[npath_prefs] = NULL;
2567 n++;
2569 } else if (strcmp(argv[n], "-gtsunpref") == 0) {
2570 if (argc < n+2) {
2571 fprintf(stderr, "-gtsunpref requires an argument\n");
2572 usage();
2573 return 2;
2575 path_un_prefs[npath_un_prefs++] = argv[n+1];
2576 path_un_prefs[npath_un_prefs] = NULL;
2577 n++;
2579 } else if (strcmp(argv[n], "-gtssaveprefix") == 0) {
2580 if (argc < n+2) {
2581 fprintf(stderr, "-gtssaveprefix requires an argument\n");
2582 usage();
2583 return 2;
2585 saveprefix = argv[n+1];
2586 n++;
2588 } else if (strcmp(argv[n], "-gtsfile") == 0) {
2590 struct stat sbuf;
2592 if (argc < n+2) {
2593 fprintf(stderr, "-gtsfile requires an argument\n");
2594 usage();
2595 return 2;
2598 gts_file = argv[n+1];
2600 if (stat(gts_file, &sbuf) == -1) {
2601 fprintf(stderr,
2602 "warning: %s does not exist, will be created\n",
2603 gts_file);
2604 } else {
2606 if ((zap_fp = fopen(gts_file, "r")) == NULL) {
2607 fprintf(stderr, "you lose cannot open %s\n", gts_file);
2608 usage();
2609 return 2;
2612 if (EhSymTableFpLoad(table, zap_fp) == -1) {
2613 fprintf(stderr,
2614 "error: failed reading symbols from gtsfile %s\n",
2615 argv[n+1]);
2616 usage();
2617 return 2;
2620 fclose(zap_fp);
2623 n++;
2625 } else if (strcmp(argv[n], "-gtszapsymbol") == 0) {
2626 if (argc < n+2) {
2627 fprintf(stderr, "-gtszapsymbol requires an argument\n");
2628 usage();
2629 return 2;
2632 EhSymTableSetSymbolState(table, argv[n+1], EH_SYM_ZAPPED);
2633 n++;
2635 } else if (strcmp(argv[n], "-gtsnozapsymbol") == 0) {
2636 if (argc < n+2) {
2637 fprintf(stderr, "-gtsnozapsymbol requires an argument\n");
2638 usage();
2639 return 2;
2642 EhSymTableSetSymbolState(table, argv[n+1], EH_SYM_DEFINED);
2643 n++;
2645 } else if (strcmp(argv[n], "-gtsname") == 0) {
2646 if (argc < n+2) {
2647 fprintf(stderr, "-gtsname requires an argument\n");
2648 usage();
2649 return 2;
2652 sym = EhSymTableFind(table, argv[n+1]);
2653 if (!sym)
2654 sym = EhSymNewRandomZap(argv[n+1]);
2655 n++;
2656 do_audit = 1;
2658 } else if (strcmp(argv[n], "-c") == 0) { /* do not link */
2659 in_link = 0;
2660 do_link = 0;
2661 } else if (strcmp(argv[n], "-S") == 0) { /* do not assem */
2662 do_assem = 0;
2663 } else if (strcmp(argv[n], "-o") == 0) { /* parse through */
2664 arg_buf[nargs++] = argv[n++];
2665 arg_buf[nargs++] = argv[n];
2666 arg_buf[nargs] = NULL;
2667 } else if (strcmp((suffix = suffix_name(argv[n])), ".cpp") == 0
2669 strcmp(suffix, ".c") == 0
2671 strcmp(suffix, ".s") == 0) {
2672 char pathname[MAXPATHLEN];
2674 make_relative_pathname(pathname, ".", rootdir);
2676 source = EhSourceNew(argv[n], arg_buf, pathname);
2678 rv = EhSourceCompile(source,
2679 table,
2680 verbosity,
2681 TRUE, /* compile, .s files ignore anyway */
2682 (do_audit + do_zap),
2683 do_assem);
2684 if (rv == -1)
2685 return 1;
2687 #if 0
2688 EhSourceAdjustPathname(source, rootdir);
2689 #endif
2691 } else if (strcmp(suffix, ".o") == 0 || strcmp(suffix, ".a") == 0) {
2693 if (fileListFind(o_list, argv[n]) == NULL) {
2694 fileListAppend(&o_list, argv[n]);
2695 } else {
2696 fprintf(stderr,
2697 "%s repeated on command line - ignored\n",
2698 argv[n]);
2700 arg_buf[nargs++] = argv[n];
2701 arg_buf[nargs] = NULL;
2703 } else if (strncmp(argv[n], "-L", 2) == 0) {
2704 EhDirMapAddDirectory(dmap, &argv[n][2]);
2705 } else if (strncmp(argv[n], "-l", 2) == 0) {
2706 char pathbuf[MAXPATHLEN];
2707 name = EhDirMapGetLibName(dmap, &argv[n][2], pathbuf);
2708 if (name != NULL) {
2709 if (fileListFind(o_list, name) == NULL) {
2710 fileListAppend(&o_list, name);
2711 } else {
2712 fprintf(stderr,
2713 "%s repeated on command line - ignored\n",
2714 name);
2716 } else {
2717 fprintf(stderr,
2718 "unable to resolve library reference %s - ignoring\n",
2719 argv[n]);
2721 arg_buf[nargs++] = argv[n];
2722 arg_buf[nargs] = NULL;
2723 } else {
2724 arg_buf[nargs++] = argv[n];
2725 arg_buf[nargs] = NULL;
2730 * Analyse objects.
2732 if (o_list != NULL) {
2733 for (list = o_list; list != NULL; list = list->next) {
2735 if (eh_process_file(list->name, table, rootdir)) {
2736 fprintf(stderr, "oops we died around %s\n", list->name);
2737 return 1;
2741 /* look for unused objects */
2742 EhSymTableMap(table, object_nusers_mappee, 0);
2745 if (do_summary) {
2746 print_summary(table);
2749 if (do_dump) {
2750 print_dump(table);
2753 if (!in_link && gts_file != NULL) {
2754 FILE* zap_fp;
2755 if ((zap_fp = fopen(gts_file, "w")) == NULL) {
2756 perror(0);
2757 usage();
2758 return 2;
2761 EhSymTableFpDump(table, zap_fp);
2762 fclose(zap_fp);
2763 return 0;
2767 * Now the fun really starts.
2769 if (do_recompile) {
2770 char** pp = NULL;
2771 char** up = NULL;
2773 if (npath_prefs > 0)
2774 pp = path_prefs;
2776 if (npath_un_prefs > 0)
2777 up = path_un_prefs;
2779 if (!do_collect)
2780 gts_file = NULL;
2782 rv = do_recompilation(table, gts_file, max_globals, pp, up, rootdir,
2783 verbosity);
2784 if (rv == -1)
2785 return 1;
2789 * Finally.
2791 if (do_link) {
2793 int status;
2795 arg_buf[nargs+1] = NULL;
2796 for (n = nargs; n > 0; n--)
2797 arg_buf[n] = arg_buf[n-1];
2798 arg_buf[0] = LD_COMMAND;
2800 status = do_command("link", arg_buf, verbosity);
2802 if (status == -1)
2803 return 3;
2804 else
2805 return status;
2808 return 0;