1 /* Driver for Minix compilers.
2 Written june 1987 by Ceriel J.H. Jacobs, partly derived from old
3 cc-driver, written by Erik Baalbergen.
4 This driver is mostly table-driven, the table being in the form of
5 some global initialized structures.
18 /* Paths. (Executables in /usr are first tried with /usr stripped off.) */
19 #define SHELL "/bin/sh"
20 #define PP "/usr/lib/ncpp"
21 #define IRREL "/usr/lib/irrel"
22 #define CEM "/usr/lib/ncem"
23 #define M2EM "/usr/lib/nm2em"
24 #define ENCODE "/usr/lib/em_encode"
25 #define OPT "/usr/lib/nopt"
26 #define CG "/usr/lib/ncg"
27 #define AS "/usr/lib/as"
28 #define LD "/usr/lib/ld"
29 #define CV "/usr/lib/cv"
30 #define LIBDIR "/usr/lib"
31 #define CRT "/usr/lib/ncrtso.o"
32 #define PEM "/usr/lib/npem"
33 #define PRT "/usr/lib/nprtso.o"
34 #define M2RT "/usr/lib/nm2rtso.o"
35 #define LIBC "/usr/lib/libd.a", "/usr/lib/libc.a"
36 #define LIBP "/usr/lib/libp.a", "/usr/lib/libc.a"
37 #define LIBM2 "/usr/lib/libm2.a", "/usr/lib/libc.a"
38 #define END "/usr/lib/libe.a", "/usr/lib/end.a"
39 #define M2DEF "-I/usr/lib/m2"
42 /* every pass that this program knows about has associated with it
43 a structure, containing such information as its name, where it
44 resides, the flags it accepts, and the like.
47 char *p_name
; /* name of this pass */
48 char *p_path
; /* where is it */
49 char *p_from
; /* suffix of source (comma-separated list) */
50 char *p_to
; /* suffix of destination */
51 char *p_acceptflags
; /* comma separated list; format:
56 where a star matches a, possibly empty,
60 #define INPUT 01 /* needs input file as argument */
61 #define OUTPUT 02 /* needs output file as argument */
62 #define LOADER 04 /* this pass is the loader */
63 #define STDIN 010 /* reads from standard input */
64 #define STDOUT 020 /* writes on standard output */
65 #define NOCLEAN 040 /* do not remove target if this pass fails */
66 #define O_OUTPUT 0100 /* -o outputfile, hack for as */
67 #define PREPALWAYS 0200 /* always to be preprocessed */
68 #define PREPCOND 0400 /* preprocessed when starting with '#' */
69 #define PREPNOLN 01000 /* suppress line number info (cpp -P) */
76 /* Every language handled by this program has a "compile" structure
77 associated with it, describing the start-suffix, how the driver for
78 this language is called, which passes must be called, which flags
79 and arguments must be passed to these passes, etc.
80 The language is determined by the suffix of the argument program.
81 However, if this suffix does not determine a language (DEFLANG),
83 Notice that the 's' suffix does not determine a language, because
84 the input file could have been derived from f.i. a C-program.
85 So, if you use "cc x.s", the C-runtime system will be used, but if
86 you use "as x.s", it will not.
89 char *c_suffix
; /* starting suffix of this list of passes */
90 char *c_callname
; /* affects runtime system loaded with program */
92 char *pp_name
; /* name of the pass */
93 char *pp_head
[MAXHEAD
]; /* args in front of filename */
94 char *pp_tail
[MAXTAIL
]; /* args after filename */
97 #define DEFLANG 010 /* this suffix determines a language */
100 struct passinfo passinfo
[] = {
101 { "cpp", PP
, "CPP", "i", "wo=o,I*,D*,U*,P", INPUT
|STDOUT
},
102 { "irrel", IRREL
, "i", "i", "m", INPUT
},
103 { "cem", CEM
, "i,c", "k", "m=o,p,wa=a,wo=o,ws=s,w,T*", INPUT
|OUTPUT
|PREPALWAYS
},
104 { "pc", PEM
, "i,p", "k", "n=L,w,a,A,R", INPUT
|OUTPUT
|PREPCOND
},
105 { "m2", M2EM
, "i,mod", "k", "n=L,w*,A,R,W*,3,I*", INPUT
|OUTPUT
|PREPCOND
},
106 { "encode", ENCODE
, "i,e", "k", "", INPUT
|STDOUT
|PREPCOND
|PREPNOLN
},
107 { "opt", OPT
, "k", "m", "", STDIN
|STDOUT
},
108 { "cg", CG
, "m", "s", "O=p4", INPUT
|OUTPUT
},
109 { "as", AS
, "i,s", "o", "T*", INPUT
|O_OUTPUT
|PREPCOND
},
110 { "ld", LD
, "o", "out", "i,s", INPUT
|LOADER
}, /* changed */
111 { "cv", CV
, "out", 0, "", INPUT
|OUTPUT
|NOCLEAN
}, /* must come after loader */
115 #define PREP_FLAGS "-D_EM_WSIZE=2", "-D_EM_PSIZE=2", "-D_EM_SSIZE=2", \
116 "-D_EM_LSIZE=4", "-D_EM_FSIZE=4", "-D_EM_DSIZE=8", \
117 "-D__ACK__", "-D__minix", "-D__i86"
119 struct pass preprocessor
= { "cpp",
124 struct pass prepnoln
= { "cpp",
129 struct pass irrel
= { "irrel",
133 /* The "*" in the arguments for the loader indicates the place where the
134 * fp-emulation library should come.
136 struct compile passes
[] = {
138 { { "cem", {"-L"}, {0} }, /* changed */
141 { "as", {"-"}, {0} },
142 { "ld", {CRT
}, /* changed */
149 { { "pc", {0}, {0} },
152 { "as", {"-"}, {0} },
161 { { "m2", {M2DEF
}, {0} },
164 { "as", {"-"}, {0} },
173 { { "encode", {0}, {0}},
176 { "as", {"-"}, {0} },
177 { "ld", {0}, {"*", END
}},
188 { { "cpp", {PREP_FLAGS
}, {0}}
195 #define MAXARGC 150 /* maximum number of arguments allowed in a list */
196 #define USTR_SIZE 64 /* maximum length of string variable */
198 typedef char USTRING
[USTR_SIZE
];
202 char *al_argv
[MAXARGC
];
205 struct arglist CALLVEC
;
209 char *o_FILE
= "a.out"; /* default name for executable file */
211 #define init(a) ((a)->al_argc = 1)
212 #define cleanup(str) (str && remove(str))
229 struct arglist SRCFILES
;
230 struct arglist LDIRS
;
231 struct arglist LDFILES
;
232 struct arglist GEN_LDFILES
;
233 struct arglist FLAGS
;
235 char *tmpdir
= "/tmp";
238 struct compile
*compbase
;
240 struct passinfo
*loaderinfo
;
244 _PROTOTYPE(char *library
, (char *nm
));
245 _PROTOTYPE(void trapcc
, (int sig
));
246 _PROTOTYPE(int main
, (int argc
, char *argv
[]));
247 _PROTOTYPE(int remove
, (char *str
));
248 _PROTOTYPE(char *alloc
, (unsigned u
));
249 _PROTOTYPE(int append
, (struct arglist
*al
, char *arg
));
250 _PROTOTYPE(int concat
, (struct arglist
*al1
, struct arglist
*al2
));
251 _PROTOTYPE(char *mkstr
, (char *dst
, char *arg1
, char *arg2
, char *arg3
));
252 _PROTOTYPE(int basename
, (char *str
, char *dst
));
253 _PROTOTYPE(char *extension
, (char *fln
));
254 _PROTOTYPE(int runvec
, (struct arglist
*vec
, struct passinfo
*pass
, char *in
, char *out
));
255 _PROTOTYPE(int prnum
, (unsigned x
));
256 _PROTOTYPE(int prs
, (char *str
));
257 _PROTOTYPE(int panic
, (char *str
));
258 _PROTOTYPE(int pr_vec
, (struct arglist
*vec
));
259 _PROTOTYPE(int ex_vec
, (struct arglist
*vec
));
260 _PROTOTYPE(int mktempname
, (char *nm
));
261 _PROTOTYPE(int mkbase
, (void));
262 _PROTOTYPE(int mkloader
, (void));
263 _PROTOTYPE(int needsprep
, (char *name
));
264 _PROTOTYPE(int cfile
, (char *name
));
265 _PROTOTYPE(char *apply
, (struct passinfo
*pinf
, struct compile
*cp
, char *name
, int passindex
, int noremove
, int first
, char *resultname
));
266 _PROTOTYPE(int applicable
, (struct passinfo
*pinf
, char *suffix
));
267 _PROTOTYPE(char *process
, (char *name
, int noremove
));
268 _PROTOTYPE(int mkvec
, (struct arglist
*call
, char *in
, char *out
, struct pass
*pass
, struct passinfo
*pinf
));
269 _PROTOTYPE(int callld
, (struct arglist
*in
, char *out
, struct pass
*pass
, struct passinfo
*pinf
));
270 _PROTOTYPE(int clean
, (struct arglist
*c
));
271 _PROTOTYPE(int scanflags
, (struct arglist
*call
, struct passinfo
*pinf
));
282 for (Lcount
= 0; Lcount
< LDIRS
.al_argc
; Lcount
++) {
283 mkstr(f
, LDIRS
.al_argv
[Lcount
], "/lib", nm
);
285 if (access(f
, 0) != 0) {
286 f
[strlen(f
)-1] = 'a';
287 if (access(f
, 0) != 0) continue;
291 mkstr(f
, LIBDIR
, "/lib", nm
);
293 if (access(f
, 0) != 0) {
294 int i
= strlen(f
) - 1;
296 if (access(f
, 0) != 0) f
[i
] = 'A';
304 signal(sig
, SIG_IGN
);
305 if (kids
!= -1) kill(kids
, sig
);
319 maxLlen
= strlen(LIBDIR
);
324 if (signal(SIGHUP
, SIG_IGN
) != SIG_IGN
)
325 signal(SIGHUP
, trapcc
);
326 if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
)
327 signal(SIGINT
, trapcc
);
328 if (signal(SIGQUIT
, SIG_IGN
) != SIG_IGN
)
329 signal(SIGQUIT
, trapcc
);
331 if (*(str
= *argv
++) != '-' || str
[1] == 0) {
332 append(&SRCFILES
, str
);
336 if (strcmp(str
, "-com") == 0) {
339 if (strcmp(str
, "-sep") == 0) {
346 if (str
[2] == '.') stopsuffix
= str
+ 3;
349 fp_lib
= (strcmp(str
+2, "hard") != 0);
356 append(&LDIRS
, &str
[2]);
357 count
= strlen(&str
[2]);
358 if (count
> maxLlen
) maxLlen
= count
;
361 append(&SRCFILES
, library(&str
[2]));
364 /* Use -m, ignore -mxxx. */
365 if (str
[2] == 0) append(&FLAGS
, str
);
388 /* save temporaries */
393 /* no runtime start-off */
394 loader
->pp_head
[0] = 0;
410 if (i_flag
) append(&FLAGS
, "-i");
414 count
= SRCFILES
.al_argc
;
415 argvec
= &(SRCFILES
.al_argv
[0]);
417 while (count
-- > 0) {
422 file
= process(file
, 1);
424 if (file
&& ! stopsuffix
) append(&LDFILES
, file
);
430 if (RET_CODE
== 0 && LDFILES
.al_argc
> 0) {
431 register struct passinfo
*pp
= passinfo
;
433 while (!(pp
->p_flags
& LOADER
)) pp
++;
434 mkstr(newfil
, tmpname
, pp
->p_to
, "");
435 callld(&LDFILES
, !((pp
+1)->p_name
) ? o_FILE
: newfil
, loader
, pp
);
437 register int i
= GEN_LDFILES
.al_argc
;
440 remove(GEN_LDFILES
.al_argv
[i
]);
441 free(GEN_LDFILES
.al_argv
[i
]);
443 if ((++pp
)->p_name
) {
470 register char *p
= malloc(u
);
472 if (p
== 0) panic("no space\n");
480 char *a
= alloc((unsigned) (strlen(arg
) + 1));
483 if (al
->al_argc
>= MAXARGC
)
484 panic("argument list overflow\n");
485 al
->al_argv
[(al
->al_argc
)++] = a
;
489 struct arglist
*al1
, *al2
;
491 register i
= al2
->al_argc
;
492 register char **p
= &(al1
->al_argv
[al1
->al_argc
]);
493 register char **q
= &(al2
->al_argv
[0]);
495 if ((al1
->al_argc
+= i
) >= MAXARGC
)
496 panic("argument list overflow\n");
502 mkstr(dst
, arg1
, arg2
, arg3
)
503 char *dst
, *arg1
, *arg2
, *arg3
;
506 register char *q
= dst
;
524 register char *p1
= str
;
525 register char *p2
= p1
;
531 while (*p1
!= '.' && p1
> p2
) p1
--;
534 while (*dst
++ = *p2
++);
538 while (*dst
++ = *p2
++);
545 register char *fn
= fln
;
548 while (fn
> fln
&& *fn
!= '.') fn
--;
549 if (fn
!= fln
) return fn
+1;
553 runvec(vec
, pass
, in
, out
)
555 struct passinfo
*pass
;
562 strncmp(vec
->al_argv
[1], "/usr/", 5) == 0
564 access(vec
->al_argv
[1] + 4, 1) == 0
566 vec
->al_argv
[1] += 4;
572 if (pass
->p_flags
& STDIN
) {
576 if (pass
->p_flags
& STDOUT
&& !E_flag
) {
583 if (shifted
) vec
->al_argv
[1] -= 4;
587 if ((pid
= fork()) == 0) { /* start up the process */
588 if (pass
->p_flags
& STDIN
&& strcmp(in
, "-") != 0) {
589 /* redirect standard input */
591 if (open(in
, 0) != 0)
592 panic("cannot open input file\n");
594 if (pass
->p_flags
& STDOUT
&& !E_flag
) {
595 /* redirect standard output */
597 if (creat(out
, 0666) != 1)
598 panic("cannot create output file\n");
603 panic("no more processes\n");
606 if (status
) switch(status
& 0177) {
614 if (E_flag
&& (status
& 0177) == SIGPIPE
) break;
615 prs(vec
->al_argv
[1]);
616 prs(" died with signal ");
617 prnum(status
& 0177);
620 if (shifted
) vec
->al_argv
[1] -= 4;
623 return status
? ((RET_CODE
= 1), 0) : 1;
629 static char numbuf
[8]; /* though it prints at most 3 characters */
630 register char *cp
= numbuf
+ sizeof(numbuf
) - 1;
634 *--cp
= (x
% 10) + '0';
646 write(2, str
, strlen(str
));
657 register struct arglist
*vec
;
659 register char **ap
= &vec
->al_argv
[1];
661 vec
->al_argv
[vec
->al_argc
] = 0;
673 register struct arglist
*vec
;
677 vec
->al_argv
[vec
->al_argc
] = 0;
678 execv(vec
->al_argv
[1], &(vec
->al_argv
[1]));
679 if (errno
== ENOEXEC
) { /* not an a.out, try it with the SHELL */
680 vec
->al_argv
[0] = SHELL
;
681 execv(SHELL
, &(vec
->al_argv
[0]));
683 if (access(vec
->al_argv
[1], 1) == 0) {
684 /* File is executable. */
685 prs("Cannot execute ");
686 prs(vec
->al_argv
[1]);
687 prs(". Not enough memory.\n");
688 prs("Reduce the memory use of your system and try again\n");
690 prs(vec
->al_argv
[1]);
691 prs(" is not executable\n");
700 register int pid
= getpid();
702 mkstr(nm
, tmpdir
, "/", compbase
->c_callname
);
705 for (i
= 9; i
> 3; i
--) {
706 *nm
++ = (pid
% 10) + '0';
710 *nm
++ = '\0'; /* null termination */
715 register struct compile
*p
= passes
;
719 basename(ProgCall
, callname
);
720 len
= strlen(callname
);
721 while (p
->c_suffix
) {
722 if (strcmp(p
->c_callname
, callname
+len
-strlen(p
->c_callname
)) == 0) {
729 /* we should not get here */
730 panic("internal error\n");
735 register struct passinfo
*p
= passinfo
;
736 register struct pass
*pass
;
738 while (!(p
->p_flags
& LOADER
)) p
++;
740 pass
= &(compbase
->c_passes
[0]);
741 while (strcmp(pass
->pp_name
, p
->p_name
)) pass
++;
752 if (file
<0) return 0;
753 if (read(file
, &fc
, 1) != 1) fc
= 0;
761 while (*name
!= '\0' && *name
!= '.')
764 if (*name
== '\0') return 0;
765 return (*++name
== 'c' && *++name
== '\0');
769 apply(pinf
, cp
, name
, passindex
, noremove
, first
, resultname
)
770 register struct passinfo
*pinf
;
771 register struct compile
*cp
;
772 char *name
, *resultname
;
774 /* Apply a pass, indicated by "pinf", with args in
775 cp->c_passes[passindex], to name "name", leaving the result
776 in a file with name "resultname", concatenated with result
778 When neccessary, the preprocessor is run first.
779 If "noremove" is NOT set, the file "name" is removed.
782 struct arglist
*call
= &CALLVEC
;
783 struct pass
*pass
= &(cp
->c_passes
[passindex
]);
786 if ( /* this pass is the first pass */
789 ( /* preprocessor always needed */
790 (pinf
->p_flags
& PREPALWAYS
)
791 ||/* or only when "needsprep" says so */
792 ( (pinf
->p_flags
& PREPCOND
) && needsprep(name
))
795 mkstr(newfil
, tmpname
, passinfo
[0].p_to
, "");
796 mkvec(call
, name
, newfil
,
797 (pinf
->p_flags
& PREPNOLN
) ? &prepnoln
: &preprocessor
,
799 if (! runvec(call
, &passinfo
[0], name
, newfil
)) {
804 /* A .c file must always be mishandled by irrel. */
807 mkvec(call
, newfil
, newfil
, &irrel
, &passinfo
[1]);
808 if (! runvec(call
, &passinfo
[1], newfil
, newfil
)) {
813 strcpy(curfil
, newfil
);
818 if (pinf
->p_to
) outname
= mkstr(newfil
, resultname
, pinf
->p_to
, "");
819 else outname
= o_FILE
;
820 mkvec(call
, name
, outname
, pass
, pinf
);
821 if (! runvec(call
, pinf
, name
, outname
)) {
822 if (! (pinf
->p_flags
& NOCLEAN
)) cleanup(outname
);
823 if (! noremove
) cleanup(name
);
826 if (! noremove
) cleanup(name
);
827 strcpy(curfil
, newfil
);
833 applicable(pinf
, suffix
)
834 struct passinfo
*pinf
;
837 /* Return one if the pass indicated by "pinfo" is applicable to
838 a file with suffix "suffix".
840 register char *sfx
= pinf
->p_from
;
843 if (! suffix
) return 0;
846 register char *p
= sfx
;
848 while (*p
&& *p
!= ',') p
++;
849 if (l
== p
- sfx
&& strncmp(sfx
, suffix
, l
) == 0) {
852 if (*p
== ',') sfx
= p
+1;
859 process(name
, noremove
)
862 register struct compile
*cp
= passes
;
863 char *suffix
= extension(name
);
865 register struct pass
*pass
;
866 register struct passinfo
*pinf
;
869 /* -E uses the cpp pass. */
873 if (! suffix
) return name
;
875 basename(name
, base
);
877 while (cp
->c_suffix
) {
878 if ((cp
->c_flags
& DEFLANG
) &&
879 strcmp(cp
->c_suffix
, suffix
) == 0)
883 if (! cp
->c_suffix
) cp
= compbase
;
885 while (pass
->pp_name
) {
888 for (pinf
=passinfo
; strcmp(pass
->pp_name
,pinf
->p_name
);pinf
++)
890 if (! (pinf
->p_flags
& LOADER
) && applicable(pinf
, suffix
)) {
891 int cont
= ! stopsuffix
|| ! pinf
->p_to
||
892 strcmp(stopsuffix
, pinf
->p_to
) != 0;
896 (int) (pass
- cp
->c_passes
),
899 applicable(loaderinfo
, pinf
->p_to
) ||
903 first
= noremove
= 0;
905 if (!cont
|| !name
) break;
909 if (!noremove
&& name
)
910 append(&GEN_LDFILES
, name
);
914 mkvec(call
, in
, out
, pass
, pinf
)
915 struct arglist
*call
;
918 register struct passinfo
*pinf
;
923 append(call
, pinf
->p_path
);
924 scanflags(call
, pinf
);
925 if (pass
) for (i
= 0; i
< MAXHEAD
; i
++)
926 if (pass
->pp_head
[i
])
927 append(call
, pass
->pp_head
[i
]);
929 if (pinf
->p_flags
& INPUT
&& strcmp(in
, "-") != 0)
931 if (pinf
->p_flags
& OUTPUT
)
933 if (pinf
->p_flags
& O_OUTPUT
) {
937 if (pass
) for (i
= 0; i
< MAXTAIL
; i
++)
938 if (pass
->pp_tail
[i
])
939 append(call
, pass
->pp_tail
[i
]);
943 callld(in
, out
, pass
, pinf
)
947 register struct passinfo
*pinf
;
949 struct arglist
*call
= &CALLVEC
;
953 append(call
, pinf
->p_path
);
954 scanflags(call
, pinf
);
957 for (i
= 0; i
< MAXHEAD
; i
++)
958 if (pass
->pp_head
[i
])
959 append(call
, pass
->pp_head
[i
]);
961 if (pinf
->p_flags
& INPUT
)
963 if (pinf
->p_flags
& OUTPUT
)
965 for (i
= 0; i
< MAXTAIL
; i
++) {
966 if (pass
->pp_tail
[i
]) {
967 if (pass
->pp_tail
[i
][0] == '-' &&
968 pass
->pp_tail
[i
][1] == 'l') {
969 append(call
, library(&(pass
->pp_tail
[i
][2])));
971 else if (*(pass
->pp_tail
[i
]) != '*')
972 append(call
, pass
->pp_tail
[i
]);
974 append(call
, library("fp"));
977 if (! runvec(call
, pinf
, (char *) 0, out
)) {
984 register struct arglist
*c
;
988 for (i
= 1; i
< c
->al_argc
; i
++) {
995 scanflags(call
, pinf
)
996 struct arglist
*call
;
997 struct passinfo
*pinf
;
999 /* Find out which flags from FLAGS must be passed to pass "pinf",
1001 Append them to "call"
1006 for (i
= 0; i
< FLAGS
.al_argc
; i
++) {
1007 register char *q
= pinf
->p_acceptflags
;
1010 register char *p
= FLAGS
.al_argv
[i
] + 1;
1012 while (*q
&& *q
== *p
) {
1015 if (*q
== ',' || !*q
) {
1017 /* append literally */
1018 append(call
, FLAGS
.al_argv
[i
]);
1023 register char *s
= flg
;
1026 /* append literally */
1027 append(call
, FLAGS
.al_argv
[i
]);
1031 if (*q
) q
++; /* skip ',' */
1032 while (*q
&& *q
!= ',' && *q
!= '*') {
1033 /* copy replacement flag */
1038 while (*p
) *s
++ = *p
++;
1045 /* copy replacement */
1046 register char *s
= flg
;
1050 while (*q
&& *q
!= ',') *s
++ = *q
++;
1055 while (*q
&& *q
++ != ',')