1 /* $Id: cc.c,v 1.283.2.1 2014/12/06 09:52:55 ragge Exp $ */
2
3 /*-
4 * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 *
39 * Redistributions of source code and documentation must retain the above
40 * copyright notice, this list of conditions and the following disclaimer.
41 * Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditionsand the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed or owned by Caldera
47 * International, Inc.
48 * Neither the name of Caldera International, Inc. nor the names of other
49 * contributors may be used to endorse or promote products derived from
50 * this software without specific prior written permission.
51 *
52 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
53 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
54 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
55 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
56 * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
57 * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
61 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
62 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
63 * POSSIBILITY OF SUCH DAMAGE.
64 */
65
66 /*
67 * Front-end to the C compiler.
68 *
69 * Brief description of its syntax:
70 * - Files that end with .c are passed via cpp->ccom->as->ld
71 * - Files that end with .i are passed via ccom->as->ld
72 * - Files that end with .S are passed via cpp->as->ld
73 * - Files that end with .s are passed via as->ld
74 * - Files that end with .o are passed directly to ld
75 * - Multiple files may be given on the command line.
76 * - Unrecognized options are all sent directly to ld.
77 * -c or -S cannot be combined with -o if multiple files are given.
78 *
79 * This file should be rewritten readable.
80 */
81 #include "config.h"
82
83 #include <sys/types.h>
84 #ifdef HAVE_SYS_WAIT_H
85 #include <sys/wait.h>
86 #endif
87
88 #include <ctype.h>
89 #include <errno.h>
90 #include <fcntl.h>
91 #ifdef HAVE_LIBGEN_H
92 #include <libgen.h>
93 #endif
94 #include <signal.h>
95 #include <stdarg.h>
96 #include <stdio.h>
97 #include <stdlib.h>
98 #include <string.h>
99 #ifdef HAVE_UNISTD_H
100 #include <unistd.h>
101 #endif
102 #include <assert.h>
103
104 #ifdef os_win32
105 #include <windows.h>
106 #include <process.h>
107 #include <io.h>
108 #define F_OK 0x00
109 #define R_OK 0x04
110 #define W_OK 0x02
111 #define X_OK R_OK
112 #endif
113
114 #include "compat.h"
115
116 #include "macdefs.h"
117
118 #include "xalloc.h"
119 #include "strlist.h"
120
121 #include "ccconfig.h"
122 /* C command */
123
124 #define MKS(x) _MKS(x)
125 #define _MKS(x) #x
126
127 /* default program names in pcc */
128 /* May be overridden if cross-compiler is generated */
129 #ifndef CPPROGNAME
130 #define CPPROGNAME "cpp" /* cc used as cpp */
131 #endif
132 #ifndef PREPROCESSOR
133 #define PREPROCESSOR "cpp" /* "real" preprocessor name */
134 #endif
135 #ifndef COMPILER
136 #define COMPILER "ccom"
137 #endif
138 #ifndef CXXCOMPILER
139 #define CXXCOMPILER "cxxcom"
140 #endif
141 #ifndef ASSEMBLER
142 #define ASSEMBLER "as"
143 #endif
144 #ifndef LINKER
145 #define LINKER "ld"
146 #endif
147 char *passp = PREPROCESSOR;
148 char *pass0 = COMPILER;
149 char *passxx0 = CXXCOMPILER;
150 char *as = ASSEMBLER;
151 char *ld = LINKER;
152 char *sysroot = "", *isysroot;
153
154
155 /* crt files using pcc default names */
156 #ifndef CRTBEGIN_S
157 #define CRTBEGIN_S "crtbeginS.o"
158 #endif
159 #ifndef CRTEND_S
160 #define CRTEND_S "crtendS.o"
161 #endif
162 #ifndef CRTBEGIN_T
163 #define CRTBEGIN_T "crtbeginT.o"
164 #endif
165 #ifndef CRTEND_T
166 #define CRTEND_T "crtendT.o"
167 #endif
168 #ifndef CRTBEGIN
169 #define CRTBEGIN "crtbegin.o"
170 #endif
171 #ifndef CRTEND
172 #define CRTEND "crtend.o"
173 #endif
174 #ifndef CRTI
175 #define CRTI "crti.o"
176 #endif
177 #ifndef CRTN
178 #define CRTN "crtn.o"
179 #endif
180 #ifndef CRT0
181 #define CRT0 "crt0.o"
182 #endif
183 #ifndef GCRT0
184 #define GCRT0 "gcrt0.o"
185 #endif
186
187 /* preprocessor stuff */
188 #ifndef STDINC
189 #define STDINC "/usr/include/"
190 #endif
191 #ifdef MULTIARCH_PATH
192 #define STDINC_MA STDINC MULTIARCH_PATH "/"
193 #endif
194
195
196 char *cppadd[] = CPPADD;
197 char *cppmdadd[] = CPPMDADD;
198
199 /* Dynamic linker definitions, per-target */
200 #ifndef DYNLINKER
201 #define DYNLINKER { 0 }
202 #endif
203
204 /* Default libraries and search paths */
205 #ifndef PCCLIBDIR /* set by autoconf */
206 #define PCCLIBDIR NULL
207 #endif
208 #ifndef DEFLIBDIRS /* default library search paths */
209 #ifndef MULTIARCH_PATH
210 #define DEFLIBDIRS { "/usr/lib/", 0 }
211 #else
212 #define DEFLIBDIRS { "/usr/lib/", "/usr/lib/" MULTIARCH_PATH "/", 0 }
213 #endif
214 #endif
215 #ifndef DEFLIBS /* default libraries included */
216 #define DEFLIBS { "-lpcc", "-lc", "-lpcc", 0 }
217 #endif
218 #ifndef DEFPROFLIBS /* default profiling libraries */
219 #define DEFPROFLIBS { "-lpcc", "-lc_p", "-lpcc", 0 }
220 #endif
221 #ifndef DEFCXXLIBS /* default c++ libraries */
222 #define DEFCXXLIBS { "-lp++", "-lpcc", "-lc", "-lpcc", 0 }
223 #endif
224 #ifndef STARTLABEL
225 #define STARTLABEL "__start"
226 #endif
227
228 char *dynlinker[] = DYNLINKER;
229 char *pcclibdir = PCCLIBDIR;
230 char *deflibdirs[] = DEFLIBDIRS;
231 char *deflibs[] = DEFLIBS;
232 char *defproflibs[] = DEFPROFLIBS;
233 char *defcxxlibs[] = DEFCXXLIBS;
234
235 char *outfile, *MFfile, *fname;
236 static char **lav;
237 static int lac;
238 static char *find_file(const char *file, struct strlist *path, int mode);
239 static int preprocess_input(char *input, char *output, int dodep);
240 static int compile_input(char *input, char *output);
241 static int assemble_input(char *input, char *output);
242 static int run_linker(void);
243 static int strlist_exec(struct strlist *l);
244
245 char *cat(const char *, const char *);
246 char *setsuf(char *, char);
247 int cxxsuf(char *);
248 int getsuf(char *);
249 char *getsufp(char *s);
250 int main(int, char *[]);
251 void errorx(int, char *, ...);
252 int cunlink(char *);
253 void exandrm(char *);
254 void dexit(int);
255 void idexit(int);
256 char *gettmp(void);
257 void oerror(char *);
258 char *argnxt(char *, char *);
259 char *nxtopt(char *o);
260 void setup_cpp_flags(void);
261 void setup_ccom_flags(void);
262 void setup_as_flags(void);
263 void setup_ld_flags(void);
264 static void expand_sysroot(void);
265 #ifdef os_win32
266 char *win32pathsubst(char *);
267 char *win32commandline(struct strlist *l);
268 #endif
269 int sspflag;
270 int freestanding;
271 int Sflag;
272 int cflag;
273 int gflag;
274 int rflag;
275 int vflag;
276 int tflag;
277 int Eflag;
278 int Oflag;
279 int kflag; /* generate PIC/pic code */
280 #define F_PIC 1
281 #define F_pic 2
282 int Mflag, needM, MDflag, MMDflag; /* dependencies only */
283 int pgflag;
284 int Xflag;
285 int nostartfiles, Bstatic, shared;
286 int nostdinc, nostdlib;
287 int pthreads;
288 int xgnu89, xgnu99;
289 int ascpp;
290 #ifdef CHAR_UNSIGNED
291 int xuchar = 1;
292 #else
293 int xuchar = 0;
294 #endif
295 int cxxflag;
296 int cppflag;
297 int printprogname, printfilename;
298
299 #ifdef mach_amd64
300 int amd64_i386;
301 #endif
302
303 #define match(a,b) (strcmp(a,b) == 0)
304
305 /* handle gcc warning emulations */
306 struct Wflags {
307 char *name;
308 int flags;
309 #define INWALL 1
310 } Wflags[] = {
311 { "truncate", 0 },
312 { "strict-prototypes", 0 },
313 { "missing-prototypes", 0 },
314 { "implicit-int", INWALL },
315 { "implicit-function-declaration", INWALL },
316 { "shadow", 0 },
317 { "pointer-sign", INWALL },
318 { "sign-compare", 0 },
319 { "unknown-pragmas", INWALL },
320 { "unreachable-code", 0 },
321 { "deprecated-declarations", 0 },
322 { "attributes", 0 },
323 { NULL, 0 },
324 };
325
326 #ifndef USHORT
327 /* copied from mip/manifest.h */
328 #define USHORT 5
329 #define INT 6
330 #define UNSIGNED 7
331 #endif
332
333 /*
334 * Wide char defines.
335 */
336 #if WCHAR_TYPE == USHORT
337 #define WCT "short unsigned int"
338 #define WCM "65535U"
339 #if WCHAR_SIZE != 2
340 #error WCHAR_TYPE vs. WCHAR_SIZE mismatch
341 #endif
342 #elif WCHAR_TYPE == INT
343 #define WCT "int"
344 #define WCM "2147483647"
345 #if WCHAR_SIZE != 4
346 #error WCHAR_TYPE vs. WCHAR_SIZE mismatch
347 #endif
348 #elif WCHAR_TYPE == UNSIGNED
349 #define WCT "unsigned int"
350 #define WCM "4294967295U"
351 #if WCHAR_SIZE != 4
352 #error WCHAR_TYPE vs. WCHAR_SIZE mismatch
353 #endif
354 #else
355 #error WCHAR_TYPE not defined or invalid
356 #endif
357
358 #ifdef GCC_COMPAT
359 #ifndef REGISTER_PREFIX
360 #define REGISTER_PREFIX ""
361 #endif
362 #ifndef USER_LABEL_PREFIX
363 #define USER_LABEL_PREFIX ""
364 #endif
365 #endif
366
367 #ifndef PCC_WINT_TYPE
368 #define PCC_WINT_TYPE "unsigned int"
369 #endif
370
371 #ifndef PCC_SIZE_TYPE
372 #define PCC_SIZE_TYPE "unsigned long"
373 #endif
374
375 #ifndef PCC_PTRDIFF_TYPE
376 #define PCC_PTRDIFF_TYPE "long int"
377 #endif
378
379
380 struct strlist preprocessor_flags;
381 struct strlist depflags;
382 struct strlist incdirs;
383 struct strlist user_sysincdirs;
384 struct strlist includes;
385 struct strlist sysincdirs;
386 struct strlist dirafterdirs;
387 struct strlist crtdirs;
388 struct strlist libdirs;
389 struct strlist progdirs;
390 struct strlist early_linker_flags;
391 struct strlist middle_linker_flags;
392 struct strlist late_linker_flags;
393 struct strlist inputs;
394 struct strlist assembler_flags;
395 struct strlist temp_outputs;
396 struct strlist compiler_flags;
397
398 int
main(int argc,char * argv[])399 main(int argc, char *argv[])
400 {
401 struct Wflags *Wf;
402 struct string *s;
403 char *t, *u, *argp;
404 char *msuffix;
405 int ninput, j;
406
407 lav = argv;
408 lac = argc;
409 ninput = 0;
410
411 strlist_init(&crtdirs);
412 strlist_init(&libdirs);
413 strlist_init(&progdirs);
414 strlist_init(&preprocessor_flags);
415 strlist_init(&incdirs);
416 strlist_init(&user_sysincdirs);
417 strlist_init(&includes);
418 strlist_init(&sysincdirs);
419 strlist_init(&dirafterdirs);
420 strlist_init(&depflags);
421 strlist_init(&early_linker_flags);
422 strlist_init(&middle_linker_flags);
423 strlist_init(&late_linker_flags);
424 strlist_init(&inputs);
425 strlist_init(&assembler_flags);
426 strlist_init(&temp_outputs);
427 strlist_init(&compiler_flags);
428
429 if ((t = strrchr(argv[0], '/')))
430 t++;
431 else
432 t = argv[0];
433
434 if (match(t, "p++")) {
435 cxxflag = 1;
436 } else if (match(t, "cpp") || match(t, CPPROGNAME)) {
437 Eflag = cppflag = 1;
438 }
439
440 #ifdef PCC_EARLY_SETUP
441 PCC_EARLY_SETUP
442 #endif
443
444 #ifdef os_win32
445 /* have to prefix path early. -B may override */
446 incdir = win32pathsubst(incdir);
447 altincdir = win32pathsubst(altincdir);
448 libdir = win32pathsubst(libdir);
449 #ifdef PCCINCDIR
450 pccincdir = win32pathsubst(pccincdir);
451 pxxincdir = win32pathsubst(pxxincdir);
452 #endif
453 #ifdef PCCLIBDIR
454 pcclibdir = win32pathsubst(pcclibdir);
455 #endif
456 passp = win32pathsubst(passp);
457 pass0 = win32pathsubst(pass0);
458 #ifdef STARTFILES
459 for (i = 0; startfiles[i] != NULL; i++)
460 startfiles[i] = win32pathsubst(startfiles[i]);
461 for (i = 0; endfiles[i] != NULL; i++)
462 endfiles[i] = win32pathsubst(endfiles[i]);
463 #endif
464 #ifdef STARTFILES_T
465 for (i = 0; startfiles_T[i] != NULL; i++)
466 startfiles_T[i] = win32pathsubst(startfiles_T[i]);
467 for (i = 0; endfiles_T[i] != NULL; i++)
468 endfiles_T[i] = win32pathsubst(endfiles_T[i]);
469 #endif
470 #ifdef STARTFILES_S
471 for (i = 0; startfiles_S[i] != NULL; i++)
472 startfiles_S[i] = win32pathsubst(startfiles_S[i]);
473 for (i = 0; endfiles_S[i] != NULL; i++)
474 endfiles_S[i] = win32pathsubst(endfiles_S[i]);
475 #endif
476 #endif
477
478 while (--lac) {
479 ++lav;
480 argp = *lav;
481
482 #ifdef PCC_EARLY_ARG_CHECK
483 PCC_EARLY_ARG_CHECK
484 #endif
485
486 if (*argp != '-' || match(argp, "-")) {
487 /* Check for duplicate .o files. */
488 if (getsuf(argp) == 'o') {
489 j = 0;
490 STRLIST_FOREACH(s, &inputs)
491 if (match(argp, s->value))
492 j++;
493 if (j)
494 continue; /* skip it */
495 }
496 strlist_append(&inputs, argp);
497 ninput++;
498 continue;
499 }
500
501 switch (argp[1]) {
502 default:
503 oerror(argp);
504 break;
505
506 case '-': /* double -'s */
507 if (match(argp, "--version")) {
508 printf("%s\n", VERSSTR);
509 return 0;
510 } else if (strncmp(argp, "--sysroot=", 10) == 0) {
511 sysroot = argp + 10;
512 } else if (strcmp(argp, "--param") == 0) {
513 /* NOTHING YET */;
514 (void)nxtopt(0); /* ignore arg */
515 } else
516 oerror(argp);
517 break;
518
519 case 'B': /* other search paths for binaries */
520 t = nxtopt("-B");
521 strlist_append(&crtdirs, t);
522 strlist_append(&libdirs, t);
523 strlist_append(&progdirs, t);
524 break;
525
526 case 'C':
527 if (match(argp, "-C") || match(argp, "-CC"))
528 strlist_append(&preprocessor_flags, argp);
529 else
530 oerror(argp);
531 break;
532
533 case 'c':
534 cflag++;
535 break;
536
537 case 'd': /* debug options */
538 for (t = &argp[2]; *t; t++) {
539 if (*t == 'M')
540 strlist_append(&preprocessor_flags, "-dM");
541
542 /* ignore others */
543 }
544 break;
545
546 case 'E':
547 Eflag++;
548 break;
549
550 case 'f': /* GCC compatibility flags */
551 u = &argp[2];
552 j = 0;
553 if (strncmp(u, "no-", 3) == 0)
554 j = 1, u += 3;
555 if (match(u, "PIC") || match(u, "pic")) {
556 kflag = j ? 0 : *u == 'P' ? F_PIC : F_pic;
557 } else if (match(u, "freestanding")) {
558 freestanding = j ? 0 : 1;
559 } else if (match(u, "signed-char")) {
560 xuchar = j ? 1 : 0;
561 } else if (match(u, "unsigned-char")) {
562 xuchar = j ? 0 : 1;
563 } else if (match(u, "stack-protector") ||
564 match(u, "stack-protector-all")) {
565 sspflag = j ? 0 : 1;
566 }
567 /* silently ignore the rest */
568 break;
569
570 case 'g': /* create debug output */
571 if (argp[2] == '0')
572 gflag = 0;
573 else
574 gflag++;
575 break;
576
577
578 case 'X':
579 Xflag++;
580 break;
581
582 case 'D':
583 case 'U':
584 strlist_append(&preprocessor_flags, argp);
585 if (argp[2] != 0)
586 break;
587 strlist_append(&preprocessor_flags, nxtopt(argp));
588 break;
589
590 case 'I': /* Add include dirs */
591 strlist_append(&incdirs, nxtopt("-I"));
592 break;
593
594 case 'i':
595 if (match(argp, "-isystem")) {
596 strlist_append(&user_sysincdirs, nxtopt(0));
597 } else if (match(argp, "-include")) {
598 strlist_append(&includes, nxtopt(0));
599 } else if (match(argp, "-isysroot")) {
600 isysroot = nxtopt(0);
601 } else if (strcmp(argp, "-idirafter") == 0) {
602 strlist_append(&dirafterdirs, nxtopt(0));
603 } else
604 oerror(argp);
605 break;
606
607 case 'k': /* generate PIC code */
608 kflag = argp[2] ? argp[2] - '0' : F_pic;
609 break;
610
611 case 'l':
612 case 'L':
613 if (argp[2] == 0)
614 argp = cat(argp, nxtopt(0));
615 strlist_append(&inputs, argp);
616 break;
617
618 case 'm': /* target-dependent options */
619 #ifdef mach_amd64
620 /* need to call i386 ccom for this */
621 if (strcmp(argp, "-melf_i386") == 0) {
622 pass0 = LIBEXECDIR "/ccom_i386";
623 amd64_i386 = 1;
624 break;
625 }
626 #endif
627 strlist_append(&middle_linker_flags, argp);
628 if (argp[2] == 0) {
629 t = nxtopt(0);
630 strlist_append(&middle_linker_flags, t);
631 }
632 break;
633
634 case 'n': /* handle -n flags */
635 if (strcmp(argp, "-nostdinc") == 0)
636 nostdinc++;
637 else if (strcmp(argp, "-nostdlib") == 0) {
638 nostdlib++;
639 nostartfiles++;
640 } else if (strcmp(argp, "-nostartfiles") == 0)
641 nostartfiles = 1;
642 else if (strcmp(argp, "-nodefaultlibs") == 0)
643 nostdlib++;
644 else
645 oerror(argp);
646 break;
647
648 case 'p':
649 if (strcmp(argp, "-pg") == 0 ||
650 strcmp(argp, "-p") == 0)
651 pgflag++;
652 else if (strcmp(argp, "-pthread") == 0)
653 pthreads++;
654 else if (strcmp(argp, "-pipe") == 0)
655 /* NOTHING YET */;
656 else if (strcmp(argp, "-pedantic") == 0)
657 /* NOTHING YET */;
658 else if ((t = argnxt(argp, "-print-prog-name="))) {
659 fname = t;
660 printprogname = 1;
661 } else if ((t = argnxt(argp, "-print-file-name="))) {
662 fname = t;
663 printfilename = 1;
664 } else if (match(argp, "-print-libgcc-file-name")) {
665 fname = "libpcc.a";
666 printfilename = 1;
667 } else
668 oerror(argp);
669 break;
670
671 case 'r':
672 rflag = 1;
673 break;
674
675 case 'T':
676 strlist_append(&inputs, argp);
677 if (argp[2] == 0 ||
678 strcmp(argp, "-Ttext") == 0 ||
679 strcmp(argp, "-Tdata") == 0 ||
680 strcmp(argp, "-Tbss") == 0)
681 strlist_append(&inputs, nxtopt(0));
682 break;
683
684 case 's':
685 if (match(argp, "-shared")) {
686 shared = 1;
687 } else if (match(argp, "-static")) {
688 Bstatic = 1;
689 } else if (match(argp, "-symbolic")) {
690 strlist_append(&middle_linker_flags,
691 "-Bsymbolic");
692 } else if (strncmp(argp, "-std", 4) == 0) {
693 if (strcmp(&argp[5], "gnu99") == 0 ||
694 strcmp(&argp[5], "gnu9x") == 0)
695 xgnu99 = 1;
696 if (strcmp(&argp[5], "gnu89") == 0)
697 xgnu89 = 1;
698 } else
699 oerror(argp);
700 break;
701
702 case 'S':
703 Sflag++;
704 cflag++;
705 break;
706
707 case 't':
708 tflag++;
709 break;
710
711 case 'o':
712 if (outfile)
713 errorx(8, "too many -o");
714 outfile = nxtopt("-o");
715 break;
716
717 case 'O':
718 if (argp[2] == '\0')
719 Oflag++;
720 else if (argp[3] == '\0' &&
721 isdigit((unsigned char)argp[2]))
722 Oflag = argp[2] - '0';
723 else if (argp[3] == '\0' && argp[2] == 's')
724 Oflag = 1; /* optimize for space only */
725 else
726 oerror(argp);
727 break;
728
729 case 'P':
730 strlist_append(&preprocessor_flags, argp);
731 break;
732
733 case 'M':
734 needM = 1;
735 if (match(argp, "-M")) {
736 Mflag++;
737 strlist_append(&depflags, argp);
738 } else if (match(argp, "-MP")) {
739 strlist_append(&depflags, "-xMP");
740 } else if (match(argp, "-MF")) {
741 MFfile = nxtopt("-MF");
742 } else if (match(argp, "-MT") || match(argp, "-MQ")) {
743 t = cat("-xMT,", nxtopt("-MT"));
744 t[3] = argp[2];
745 strlist_append(&depflags, t);
746 } else if (match(argp, "-MD")) {
747 MDflag++;
748 needM = 0;
749 strlist_append(&depflags, "-M");
750 } else if (match(argp, "-MMD")) {
751 MMDflag++;
752 needM = 0;
753 strlist_append(&depflags, "-M");
754 strlist_append(&depflags, "-xMMD");
755 } else
756 oerror(argp);
757 break;
758
759 case 'v':
760 printf("%s\n", VERSSTR);
761 vflag++;
762 break;
763
764 case 'w': /* no warnings at all emitted */
765 strlist_append(&compiler_flags, "-w");
766 break;
767
768 case 'W': /* Ignore (most of) W-flags */
769 if ((t = argnxt(argp, "-Wl,"))) {
770 u = strtok(t, ",");
771 do {
772 strlist_append(&inputs, u);
773 } while ((u = strtok(NULL, ",")) != NULL);
774 } else if ((t = argnxt(argp, "-Wa,"))) {
775 u = strtok(t, ",");
776 do {
777 strlist_append(&assembler_flags, u);
778 } while ((u = strtok(NULL, ",")) != NULL);
779 } else if ((t = argnxt(argp, "-Wc,"))) {
780 u = strtok(t, ",");
781 do {
782 strlist_append(&compiler_flags, u);
783 } while ((u = strtok(NULL, ",")) != NULL);
784 } else if ((t = argnxt(argp, "-Wp,"))) {
785 u = strtok(t, ",");
786 do {
787 strlist_append(&preprocessor_flags, u);
788 } while ((u = strtok(NULL, ",")) != NULL);
789 } else if (strcmp(argp, "-Werror") == 0) {
790 strlist_append(&compiler_flags, "-Werror");
791 strlist_append(&preprocessor_flags, "-E");
792 } else if (strcmp(argp, "-Wall") == 0) {
793 for (Wf = Wflags; Wf->name; Wf++)
794 if (Wf->flags & INWALL)
795 strlist_append(&compiler_flags,
796 cat("-W", Wf->name));
797 } else if (strcmp(argp, "-WW") == 0) {
798 for (Wf = Wflags; Wf->name; Wf++)
799 strlist_append(&compiler_flags,
800 cat("-W", Wf->name));
801 } else {
802 /* pass through, if supported */
803 t = &argp[2];
804 if (strncmp(t, "no-", 3) == 0)
805 t += 3;
806 if (strncmp(t, "error=", 6) == 0)
807 t += 6;
808 for (Wf = Wflags; Wf->name; Wf++) {
809 if (strcmp(t, Wf->name) == 0)
810 strlist_append(&compiler_flags,
811 argp);
812 }
813 }
814 break;
815
816 case 'x':
817 t = nxtopt("-x");
818 if (match(t, "none"))
819 strlist_append(&inputs, ")");
820 else if (match(t, "c"))
821 strlist_append(&inputs, ")c");
822 else if (match(t, "assembler"))
823 strlist_append(&inputs, ")s");
824 else if (match(t, "assembler-with-cpp"))
825 strlist_append(&inputs, ")S");
826 else if (match(t, "c++"))
827 strlist_append(&inputs, ")c++");
828 else {
829 strlist_append(&compiler_flags, "-x");
830 strlist_append(&compiler_flags, t);
831 }
832 break;
833
834 }
835 continue;
836
837 }
838
839 /* Sanity checking */
840 if (cppflag) {
841 if (ninput == 0) {
842 strlist_append(&inputs, "-");
843 ninput++;
844 } else if (ninput > 2 || (ninput == 2 && outfile)) {
845 errorx(8, "too many files");
846 } else if (ninput == 2) {
847 outfile = STRLIST_NEXT(STRLIST_FIRST(&inputs))->value;
848 STRLIST_FIRST(&inputs)->next = NULL;
849 ninput--;
850 }
851 }
852 if (ninput == 0 && !(printprogname || printfilename))
853 errorx(8, "no input files");
854 if (outfile && (cflag || Sflag || Eflag) && ninput > 1)
855 errorx(8, "-o given with -c || -E || -S and more than one file");
856 #if 0
857 if (outfile && clist[0] && strcmp(outfile, clist[0]) == 0)
858 errorx(8, "output file will be clobbered");
859 #endif
860
861 if (needM && !Mflag && !MDflag && !MMDflag)
862 errorx(8, "to make dependencies needs -M");
863
864
865 if (signal(SIGINT, SIG_IGN) != SIG_IGN) /* interrupt */
866 signal(SIGINT, idexit);
867 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) /* terminate */
868 signal(SIGTERM, idexit);
869
870 /* after arg parsing */
871 strlist_append(&progdirs, LIBEXECDIR);
872 if (pcclibdir)
873 strlist_append(&crtdirs, pcclibdir);
874 for (j = 0; deflibdirs[j]; j++) {
875 if (sysroot)
876 deflibdirs[j] = cat(sysroot, deflibdirs[j]);
877 strlist_append(&crtdirs, deflibdirs[j]);
878 }
879
880 setup_cpp_flags();
881 setup_ccom_flags();
882 setup_as_flags();
883
884 if (isysroot == NULL)
885 isysroot = sysroot;
886 expand_sysroot();
887
888 if (printprogname) {
889 printf("%s\n", find_file(fname, &progdirs, X_OK));
890 return 0;
891 } else if (printfilename) {
892 printf("%s\n", find_file(fname, &crtdirs, R_OK));
893 return 0;
894 }
895
896 msuffix = NULL;
897 STRLIST_FOREACH(s, &inputs) {
898 char *suffix;
899 char *ifile, *ofile = NULL;
900
901 ifile = s->value;
902 if (ifile[0] == ')') { /* -x source type given */
903 msuffix = ifile[1] ? &ifile[1] : NULL;
904 continue;
905 }
906 if (ifile[0] == '-' && ifile[1] == 0)
907 suffix = msuffix ? msuffix : "c";
908 else if (ifile[0] == '-')
909 suffix = "o"; /* source files cannot begin with - */
910 else if (msuffix)
911 suffix = msuffix;
912 else
913 suffix = getsufp(ifile);
914 /*
915 * C preprocessor
916 */
917 ascpp = match(suffix, "S");
918 if (ascpp || match(suffix, "c") || cxxsuf(suffix)) {
919 /* find out next output file */
920 if (Mflag || MDflag || MMDflag) {
921 char *Mofile = NULL;
922
923 if (MFfile)
924 Mofile = MFfile;
925 else if (outfile)
926 Mofile = setsuf(outfile, 'd');
927 else if (MDflag || MMDflag)
928 Mofile = setsuf(ifile, 'd');
929 if (preprocess_input(ifile, Mofile, 1))
930 exandrm(Mofile);
931 }
932 if (Mflag)
933 continue;
934 if (Eflag) {
935 /* last pass */
936 ofile = outfile;
937 } else {
938 /* to temp file */
939 strlist_append(&temp_outputs, ofile = gettmp());
940 }
941 if (preprocess_input(ifile, ofile, 0))
942 exandrm(ofile);
943 if (Eflag)
944 continue;
945 ifile = ofile;
946 suffix = match(suffix, "S") ? "s" : "i";
947 }
948
949 /*
950 * C compiler
951 */
952 if (match(suffix, "i")) {
953 /* find out next output file */
954 if (Sflag) {
955 ofile = outfile;
956 if (outfile == NULL)
957 ofile = setsuf(s->value, 's');
958 } else
959 strlist_append(&temp_outputs, ofile = gettmp());
960 if (compile_input(ifile, ofile))
961 exandrm(ofile);
962 if (Sflag)
963 continue;
964 ifile = ofile;
965 suffix = "s";
966 }
967
968 /*
969 * Assembler
970 */
971 if (match(suffix, "s")) {
972 if (cflag) {
973 ofile = outfile;
974 if (ofile == NULL)
975 ofile = setsuf(s->value, 'o');
976 } else {
977 strlist_append(&temp_outputs, ofile = gettmp());
978 /* strlist_append linker */
979 }
980 if (assemble_input(ifile, ofile))
981 exandrm(ofile);
982 ifile = ofile;
983 }
984
985 if (ninput > 1 && !Eflag && ifile == ofile && ifile[0] != '-')
986 printf("%s:\n", ifile);
987
988 strlist_append(&middle_linker_flags, ifile);
989 }
990
991 if (cflag || Eflag || Mflag)
992 dexit(0);
993
994 /*
995 * Linker
996 */
997 setup_ld_flags();
998 if (run_linker())
999 exandrm(0);
1000
1001 #ifdef notdef
1002 strlist_free(&crtdirs);
1003 strlist_free(&libdirs);
1004 strlist_free(&progdirs);
1005 strlist_free(&incdirs);
1006 strlist_free(&preprocessor_flags);
1007 strlist_free(&user_sysincdirs);
1008 strlist_free(&includes);
1009 strlist_free(&sysincdirs);
1010 strlist_free(&dirafterdirs);
1011 strlist_free(&depflags);
1012 strlist_free(&early_linker_flags);
1013 strlist_free(&middle_linker_flags);
1014 strlist_free(&late_linker_flags);
1015 strlist_free(&inputs);
1016 strlist_free(&assembler_flags);
1017 strlist_free(&temp_outputs);
1018 strlist_free(&compiler_flags);
1019 #endif
1020 dexit(0);
1021 return 0;
1022 }
1023
1024 /*
1025 * exit and cleanup after interrupt.
1026 */
1027 void
idexit(int arg)1028 idexit(int arg)
1029 {
1030 dexit(100);
1031 }
1032
1033 /*
1034 * exit and cleanup.
1035 */
1036 void
dexit(int eval)1037 dexit(int eval)
1038 {
1039 struct string *s;
1040
1041 if (!Xflag) {
1042 STRLIST_FOREACH(s, &temp_outputs)
1043 cunlink(s->value);
1044 }
1045 exit(eval);
1046 }
1047
1048 /*
1049 * Called when something failed.
1050 */
1051 void
exandrm(char * s)1052 exandrm(char *s)
1053 {
1054 if (s && *s)
1055 strlist_append(&temp_outputs, s);
1056 dexit(1);
1057 }
1058
1059 /*
1060 * complain and exit.
1061 */
1062 void
errorx(int eval,char * s,...)1063 errorx(int eval, char *s, ...)
1064 {
1065 va_list ap;
1066
1067 va_start(ap, s);
1068 fputs("error: ", stderr);
1069 vfprintf(stderr, s, ap);
1070 putc('\n', stderr);
1071 va_end(ap);
1072 dexit(eval);
1073 }
1074
1075 static char *
find_file(const char * file,struct strlist * path,int mode)1076 find_file(const char *file, struct strlist *path, int mode)
1077 {
1078 struct string *s;
1079 char *f;
1080 size_t lf, lp;
1081 int need_sep;
1082
1083 lf = strlen(file);
1084 STRLIST_FOREACH(s, path) {
1085 lp = strlen(s->value);
1086 need_sep = (lp && s->value[lp - 1] != '/') ? 1 : 0;
1087 f = xmalloc(lp + lf + need_sep + 1);
1088 memcpy(f, s->value, lp);
1089 if (need_sep)
1090 f[lp] = '/';
1091 memcpy(f + lp + need_sep, file, lf + 1);
1092 if (access(f, mode) == 0)
1093 return f;
1094 free(f);
1095 }
1096 return xstrdup(file);
1097 }
1098
1099 static int
compile_input(char * input,char * output)1100 compile_input(char *input, char *output)
1101 {
1102 struct strlist args;
1103 int retval;
1104
1105 strlist_init(&args);
1106 strlist_append_list(&args, &compiler_flags);
1107 strlist_append(&args, input);
1108 strlist_append(&args, output);
1109 strlist_prepend(&args,
1110 find_file(cxxflag ? passxx0 : pass0, &progdirs, X_OK));
1111 retval = strlist_exec(&args);
1112 strlist_free(&args);
1113 return retval;
1114 }
1115
1116 static int
assemble_input(char * input,char * output)1117 assemble_input(char *input, char *output)
1118 {
1119 struct strlist args;
1120 int retval;
1121
1122 strlist_init(&args);
1123 #ifdef PCC_EARLY_AS_ARGS
1124 PCC_EARLY_AS_ARGS
1125 #endif
1126 strlist_append_list(&args, &assembler_flags);
1127 strlist_append(&args, input);
1128 strlist_append(&args, "-o");
1129 strlist_append(&args, output);
1130 strlist_prepend(&args,
1131 find_file(as, &progdirs, X_OK));
1132 #ifdef PCC_LATE_AS_ARGS
1133 PCC_LATE_AS_ARGS
1134 #endif
1135 retval = strlist_exec(&args);
1136 strlist_free(&args);
1137 return retval;
1138 }
1139
1140 static int
preprocess_input(char * input,char * output,int dodep)1141 preprocess_input(char *input, char *output, int dodep)
1142 {
1143 struct strlist args;
1144 struct string *s;
1145 int retval;
1146
1147 strlist_init(&args);
1148 strlist_append_list(&args, &preprocessor_flags);
1149 if (ascpp) {
1150 strlist_append(&args, "-A");
1151 strlist_append(&args, "-D__ASSEMBLER__");
1152 }
1153 STRLIST_FOREACH(s, &includes) {
1154 strlist_append(&args, "-i");
1155 strlist_append(&args, s->value);
1156 }
1157 STRLIST_FOREACH(s, &incdirs) {
1158 strlist_append(&args, "-I");
1159 strlist_append(&args, s->value);
1160 }
1161 STRLIST_FOREACH(s, &user_sysincdirs) {
1162 strlist_append(&args, "-S");
1163 strlist_append(&args, s->value);
1164 }
1165 if (!nostdinc) {
1166 STRLIST_FOREACH(s, &sysincdirs) {
1167 strlist_append(&args, "-S");
1168 strlist_append(&args, s->value);
1169 }
1170 }
1171 if (dodep)
1172 strlist_append_list(&args, &depflags);
1173 strlist_append(&args, input);
1174 if (output)
1175 strlist_append(&args, output);
1176
1177 strlist_prepend(&args, find_file(passp, &progdirs, X_OK));
1178 retval = strlist_exec(&args);
1179 strlist_free(&args);
1180 return retval;
1181 }
1182
1183 static int
run_linker(void)1184 run_linker(void)
1185 {
1186 struct strlist linker_flags;
1187 int retval;
1188
1189 if (outfile) {
1190 strlist_prepend(&early_linker_flags, outfile);
1191 strlist_prepend(&early_linker_flags, "-o");
1192 }
1193 strlist_init(&linker_flags);
1194 strlist_append_list(&linker_flags, &early_linker_flags);
1195 strlist_append_list(&linker_flags, &middle_linker_flags);
1196 strlist_append_list(&linker_flags, &late_linker_flags);
1197 strlist_prepend(&linker_flags, find_file(ld, &progdirs, X_OK));
1198
1199 retval = strlist_exec(&linker_flags);
1200
1201 strlist_free(&linker_flags);
1202 return retval;
1203 }
1204
1205 static char *cxxt[] = { "cc", "cp", "cxx", "cpp", "CPP", "c++", "C" };
1206 int
cxxsuf(char * s)1207 cxxsuf(char *s)
1208 {
1209 unsigned i;
1210 for (i = 0; i < sizeof(cxxt)/sizeof(cxxt[0]); i++)
1211 if (strcmp(s, cxxt[i]) == 0)
1212 return 1;
1213 return 0;
1214 }
1215
1216 char *
getsufp(char * s)1217 getsufp(char *s)
1218 {
1219 register char *p;
1220
1221 if ((p = strrchr(s, '.')) && p[1] != '\0')
1222 return &p[1];
1223 return "";
1224 }
1225
1226 int
getsuf(char * s)1227 getsuf(char *s)
1228 {
1229 register char *p;
1230
1231 if ((p = strrchr(s, '.')) && p[1] != '\0' && p[2] == '\0')
1232 return p[1];
1233 return(0);
1234 }
1235
1236 /*
1237 * Get basename of string s, copy it and change its suffix to ch.
1238 */
1239 char *
setsuf(char * s,char ch)1240 setsuf(char *s, char ch)
1241 {
1242 char *e, *p, *rp;
1243
1244 e = NULL;
1245 for (p = s; *p; p++) {
1246 if (*p == '/')
1247 s = p + 1;
1248 if (*p == '.')
1249 e = p;
1250 }
1251 if (s > e)
1252 e = p;
1253
1254 rp = p = xmalloc(e - s + 3);
1255 while (s < e)
1256 *p++ = *s++;
1257
1258 *p++ = '.';
1259 *p++ = ch;
1260 *p = '\0';
1261 return rp;
1262 }
1263
1264 #ifdef os_win32
1265
1266 static int
strlist_exec(struct strlist * l)1267 strlist_exec(struct strlist *l)
1268 {
1269 char *cmd;
1270 STARTUPINFO si;
1271 PROCESS_INFORMATION pi;
1272 DWORD exitCode;
1273 BOOL ok;
1274
1275 cmd = win32commandline(l);
1276 if (vflag)
1277 printf("%s\n", cmd);
1278
1279 ZeroMemory(&si, sizeof(STARTUPINFO));
1280 si.cb = sizeof(STARTUPINFO);
1281 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
1282
1283 ok = CreateProcess(NULL, // the executable program
1284 cmd, // the command line arguments
1285 NULL, // ignored
1286 NULL, // ignored
1287 TRUE, // inherit handles
1288 HIGH_PRIORITY_CLASS,
1289 NULL, // ignored
1290 NULL, // ignored
1291 &si,
1292 &pi);
1293
1294 if (!ok)
1295 errorx(100, "Can't find %s\n", STRLIST_FIRST(l)->value);
1296
1297 WaitForSingleObject(pi.hProcess, INFINITE);
1298 GetExitCodeProcess(pi.hProcess, &exitCode);
1299 CloseHandle(pi.hProcess);
1300 CloseHandle(pi.hThread);
1301
1302 return (exitCode != 0);
1303 }
1304
1305 #else
1306
1307 static int
strlist_exec(struct strlist * l)1308 strlist_exec(struct strlist *l)
1309 {
1310 sig_atomic_t exit_now = 0;
1311 sig_atomic_t child;
1312 char **argv;
1313 size_t argc;
1314 int result;
1315
1316 strlist_make_array(l, &argv, &argc);
1317 if (vflag) {
1318 printf("Calling ");
1319 strlist_print(l, stdout);
1320 printf("\n");
1321 }
1322
1323 switch ((child = fork())) {
1324 case 0:
1325 execvp(argv[0], argv);
1326 result = write(STDERR_FILENO, "Exec of ", 8);
1327 result = write(STDERR_FILENO, argv[0], strlen(argv[0]));
1328 result = write(STDERR_FILENO, " failed\n", 7);
1329 (void)result;
1330 _exit(127);
1331 case -1:
1332 errorx(1, "fork failed");
1333 default:
1334 while (waitpid(child, &result, 0) == -1 && errno == EINTR)
1335 /* nothing */(void)0;
1336 result = WEXITSTATUS(result);
1337 if (result)
1338 errorx(1, "%s terminated with status %d", argv[0], result);
1339 while (argc-- > 0)
1340 free(argv[argc]);
1341 free(argv);
1342 break;
1343 }
1344 return exit_now;
1345 }
1346
1347 #endif
1348
1349 /*
1350 * Catenate two (optional) strings together
1351 */
1352 char *
cat(const char * a,const char * b)1353 cat(const char *a, const char *b)
1354 {
1355 size_t len;
1356 char *rv;
1357
1358 len = (a ? strlen(a) : 0) + (b ? strlen(b) : 0) + 1;
1359 rv = xmalloc(len);
1360 snprintf(rv, len, "%s%s", (a ? a : ""), (b ? b : ""));
1361 return rv;
1362 }
1363
1364 int
cunlink(char * f)1365 cunlink(char *f)
1366 {
1367 if (f==0 || Xflag)
1368 return(0);
1369 return (unlink(f));
1370 }
1371
1372 #ifdef os_win32
1373 char *
gettmp(void)1374 gettmp(void)
1375 {
1376 DWORD pathSize;
1377 char pathBuffer[MAX_PATH + 1];
1378 char tempFilename[MAX_PATH];
1379 UINT uniqueNum;
1380
1381 pathSize = GetTempPath(sizeof(pathBuffer), pathBuffer);
1382 if (pathSize == 0 || pathSize > sizeof(pathBuffer))
1383 pathBuffer[0] = '\0';
1384 uniqueNum = GetTempFileName(pathBuffer, "ctm", 0, tempFilename);
1385 if (uniqueNum == 0)
1386 errorx(8, "GetTempFileName failed: path \"%s\"", pathBuffer);
1387
1388 return xstrdup(tempFilename);
1389 }
1390
1391 #else
1392
1393 char *
gettmp(void)1394 gettmp(void)
1395 {
1396 char *sfn = xstrdup("/tmp/ctm.XXXXXX");
1397 int fd = -1;
1398
1399 if ((fd = mkstemp(sfn)) == -1)
1400 errorx(8, "%s: %s\n", sfn, strerror(errno));
1401 close(fd);
1402 return sfn;
1403 }
1404 #endif
1405
1406 static void
expand_sysroot(void)1407 expand_sysroot(void)
1408 {
1409 struct string *s;
1410 struct strlist *lists[] = { &crtdirs, &sysincdirs, &incdirs,
1411 &user_sysincdirs, &libdirs, &progdirs, &dirafterdirs, NULL };
1412 const char *sysroots[] = { sysroot, isysroot, isysroot, isysroot,
1413 sysroot, sysroot, isysroot, NULL };
1414 size_t i, sysroot_len, value_len;
1415 char *path;
1416
1417 assert(sizeof(lists) / sizeof(lists[0]) ==
1418 sizeof(sysroots) / sizeof(sysroots[0]));
1419
1420 for (i = 0; lists[i] != NULL; ++i) {
1421 STRLIST_FOREACH(s, lists[i]) {
1422 if (s->value[0] != '=')
1423 continue;
1424 sysroot_len = strlen(sysroots[i]);
1425 /* Skipped '=' compensates additional space for '\0' */
1426 value_len = strlen(s->value);
1427 path = xmalloc(sysroot_len + value_len);
1428 memcpy(path, sysroots[i], sysroot_len);
1429 memcpy(path + sysroot_len, s->value + 1, value_len);
1430 free(s->value);
1431 s->value = path;
1432 }
1433 }
1434 }
1435
1436 void
oerror(char * s)1437 oerror(char *s)
1438 {
1439 errorx(8, "unknown option '%s'", s);
1440 }
1441
1442 /*
1443 * See if m matches the beginning of string str, if it does return the
1444 * remaining of str, otherwise NULL.
1445 */
1446 char *
argnxt(char * str,char * m)1447 argnxt(char *str, char *m)
1448 {
1449 if (strncmp(str, m, strlen(m)))
1450 return NULL; /* No match */
1451 return str + strlen(m);
1452 }
1453
1454 /*
1455 * Return next argument to option, or complain.
1456 */
1457 char *
nxtopt(char * o)1458 nxtopt(char *o)
1459 {
1460 int l;
1461
1462 if (o != NULL) {
1463 l = strlen(o);
1464 if (lav[0][l] != 0)
1465 return &lav[0][l];
1466 }
1467 if (lac == 0)
1468 errorx(8, "missing argument to '%s'", o);
1469 lav++;
1470 lac--;
1471 return lav[0];
1472 }
1473
1474 struct flgcheck {
1475 int *flag;
1476 int set;
1477 char *def;
1478 } cppflgcheck[] = {
1479 { &vflag, 1, "-v" },
1480 { &freestanding, 1, "-D__STDC_HOSTED__=0" },
1481 { &freestanding, 0, "-D__STDC_HOSTED__=1" },
1482 { &cxxflag, 1, "-D__cplusplus" },
1483 { &xuchar, 1, "-D__CHAR_UNSIGNED__" },
1484 { &sspflag, 1, "-D__SSP__" },
1485 { &pthreads, 1, "-D_PTHREADS" },
1486 { &Oflag, 1, "-D__OPTIMIZE__" },
1487 { &tflag, 1, "-t" },
1488 { &kflag, 1, "-D__PIC__" },
1489 { 0 },
1490 };
1491
1492 static void
cksetflags(struct flgcheck * fs,struct strlist * sl,int which)1493 cksetflags(struct flgcheck *fs, struct strlist *sl, int which)
1494 {
1495 void (*fn)(struct strlist *, const char *);
1496
1497 fn = which == 'p' ? strlist_prepend : strlist_append;
1498 for (; fs->flag; fs++) {
1499 if (fs->set && *fs->flag)
1500 fn(sl, fs->def);
1501 if (!fs->set && !*fs->flag)
1502 fn(sl, fs->def);
1503 }
1504 }
1505
1506 #ifndef TARGET_LE
1507 #define TARGET_LE 1
1508 #define TARGET_BE 2
1509 #define TARGET_PDP 3
1510 #define TARGET_ANY 4
1511 #endif
1512
1513 static char *defflags[] = {
1514 "-D__PCC__=" MKS(PCC_MAJOR),
1515 "-D__PCC_MINOR__=" MKS(PCC_MINOR),
1516 "-D__PCC_MINORMINOR__=" MKS(PCC_MINORMINOR),
1517 "-D__VERSION__=" MKS(VERSSTR),
1518 "-D__SCHAR_MAX__=" MKS(MAX_CHAR),
1519 "-D__SHRT_MAX__=" MKS(MAX_SHORT),
1520 "-D__INT_MAX__=" MKS(MAX_INT),
1521 "-D__LONG_MAX__=" MKS(MAX_LONG),
1522 "-D__LONG_LONG_MAX__=" MKS(MAX_LONGLONG),
1523
1524 "-D__STDC_ISO_10646__=200009L",
1525 "-D__WCHAR_TYPE__=" WCT,
1526 "-D__SIZEOF_WCHAR_T__=" MKS(WCHAR_SIZE),
1527 "-D__WCHAR_MAX__=" WCM,
1528 "-D__WINT_TYPE__=" PCC_WINT_TYPE,
1529 "-D__SIZE_TYPE__=" PCC_SIZE_TYPE,
1530 "-D__PTRDIFF_TYPE__=" PCC_PTRDIFF_TYPE,
1531 "-D__SIZEOF_WINT_T__=4",
1532 "-D__ORDER_LITTLE_ENDIAN__=1234",
1533 "-D__ORDER_BIG_ENDIAN__=4321",
1534 "-D__ORDER_PDP_ENDIAN__=3412",
1535 /*
1536 * These should probably be changeable during runtime...
1537 */
1538 #if TARGET_ENDIAN == TARGET_BE
1539 "-D__FLOAT_WORD_ORDER__=__ORDER_BIG_ENDIAN__",
1540 "-D__BYTE_ORDER__=__ORDER_BIG_ENDIAN__",
1541 #elif TARGET_ENDIAN == TARGET_PDP
1542 "-D__FLOAT_WORD_ORDER__=__ORDER_PDP_ENDIAN__",
1543 "-D__BYTE_ORDER__=__ORDER_PDP_ENDIAN__",
1544 #elif TARGET_ENDIAN == TARGET_LE
1545 "-D__FLOAT_WORD_ORDER__=__ORDER_LITTLE_ENDIAN__",
1546 "-D__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__",
1547 #else
1548 #error Unknown endian...
1549 #endif
1550 };
1551
1552 static char *gcppflags[] = {
1553 #ifndef os_win32
1554 #ifdef GCC_COMPAT
1555 "-D__GNUC__=4",
1556 "-D__GNUC_MINOR__=3",
1557 "-D__GNUC_PATCHLEVEL__=1",
1558 "-D__REGISTER_PREFIX__=" REGISTER_PREFIX,
1559 "-D__USER_LABEL_PREFIX__=" USER_LABEL_PREFIX,
1560 #if SZLONG == 64
1561 "-D__SIZEOF_LONG__=8",
1562 #elif SZLONG == 32
1563 "-D__SIZEOF_LONG__=4",
1564 #endif
1565 #if SZPOINT(CHAR) == 64
1566 "-D__SIZEOF_POINTER__=8",
1567 #elif SZPOINT(CHAR) == 32
1568 "-D__SIZEOF_POINTER__=4",
1569 #endif
1570 #endif
1571 #endif
1572 };
1573
1574 /* These should _not_ be defined here */
1575 static char *fpflags[] = {
1576 #ifdef TARGET_FLT_EVAL_METHOD
1577 "-D__FLT_EVAL_METHOD__=" MKS(TARGET_FLT_EVAL_METHOD),
1578 #endif
1579 #if defined(os_darwin) || defined(os_netbsd)
1580 "-D__FLT_RADIX__=2",
1581 #if defined(mach_vax)
1582 "-D__FLT_DIG__=6",
1583 "-D__FLT_EPSILON__=1.19209290e-07F",
1584 "-D__FLT_MANT_DIG__=24",
1585 "-D__FLT_MAX_10_EXP__=38",
1586 "-D__FLT_MAX_EXP__=127",
1587 "-D__FLT_MAX__=1.70141173e+38F",
1588 "-D__FLT_MIN_10_EXP__=(-38)",
1589 "-D__FLT_MIN_EXP__=(-127)",
1590 "-D__FLT_MIN__=2.93873588e-39F",
1591 "-D__DBL_DIG__=16",
1592 "-D__DBL_EPSILON__=2.77555756156289135e-17",
1593 "-D__DBL_MANT_DIG__=56",
1594 "-D__DBL_MAX_10_EXP__=38",
1595 "-D__DBL_MAX_EXP__=127",
1596 "-D__DBL_MAX__=1.701411834604692294e+38",
1597 "-D__DBL_MIN_10_EXP__=(-38)",
1598 "-D__DBL_MIN_EXP__=(-127)",
1599 "-D__DBL_MIN__=2.938735877055718770e-39",
1600 #else
1601 "-D__FLT_DIG__=6",
1602 "-D__FLT_EPSILON__=1.19209290e-07F",
1603 "-D__FLT_MANT_DIG__=24",
1604 "-D__FLT_MAX_10_EXP__=38",
1605 "-D__FLT_MAX_EXP__=128",
1606 "-D__FLT_MAX__=3.40282347e+38F",
1607 "-D__FLT_MIN_10_EXP__=(-37)",
1608 "-D__FLT_MIN_EXP__=(-125)",
1609 "-D__FLT_MIN__=1.17549435e-38F",
1610 "-D__DBL_DIG__=15",
1611 "-D__DBL_EPSILON__=2.2204460492503131e-16",
1612 "-D__DBL_MANT_DIG__=53",
1613 "-D__DBL_MAX_10_EXP__=308",
1614 "-D__DBL_MAX_EXP__=1024",
1615 "-D__DBL_MAX__=1.7976931348623157e+308",
1616 "-D__DBL_MIN_10_EXP__=(-307)",
1617 "-D__DBL_MIN_EXP__=(-1021)",
1618 "-D__DBL_MIN__=2.2250738585072014e-308",
1619 #endif
1620 #if defined(mach_i386) || defined(mach_amd64)
1621 "-D__LDBL_DIG__=18",
1622 "-D__LDBL_EPSILON__=1.08420217248550443401e-19L",
1623 "-D__LDBL_MANT_DIG__=64",
1624 "-D__LDBL_MAX_10_EXP__=4932",
1625 "-D__LDBL_MAX_EXP__=16384",
1626 "-D__LDBL_MAX__=1.18973149535723176502e+4932L",
1627 "-D__LDBL_MIN_10_EXP__=(-4931)",
1628 "-D__LDBL_MIN_EXP__=(-16381)",
1629 "-D__LDBL_MIN__=3.36210314311209350626e-4932L",
1630 #elif defined(mach_vax)
1631 "-D__LDBL_DIG__=16",
1632 "-D__LDBL_EPSILON__=2.77555756156289135e-17",
1633 "-D__LDBL_MANT_DIG__=56",
1634 "-D__LDBL_MAX_10_EXP__=38",
1635 "-D__LDBL_MAX_EXP__=127",
1636 "-D__LDBL_MAX__=1.701411834604692294e+38",
1637 "-D__LDBL_MIN_10_EXP__=(-38)",
1638 "-D__LDBL_MIN_EXP__=(-127)",
1639 "-D__LDBL_MIN__=2.938735877055718770e-39",
1640 #else
1641 "-D__LDBL_DIG__=15",
1642 "-D__LDBL_EPSILON__=2.2204460492503131e-16",
1643 "-D__LDBL_MANT_DIG__=53",
1644 "-D__LDBL_MAX_10_EXP__=308",
1645 "-D__LDBL_MAX_EXP__=1024",
1646 "-D__LDBL_MAX__=1.7976931348623157e+308",
1647 "-D__LDBL_MIN_10_EXP__=(-307)",
1648 "-D__LDBL_MIN_EXP__=(-1021)",
1649 "-D__LDBL_MIN__=2.2250738585072014e-308",
1650 #endif
1651 #endif
1652 };
1653
1654 /*
1655 * Configure the standard cpp flags.
1656 */
1657 void
setup_cpp_flags(void)1658 setup_cpp_flags(void)
1659 {
1660 int i;
1661
1662 /* a bunch of misc defines */
1663 for (i = 0; i < (int)sizeof(defflags)/(int)sizeof(char *); i++)
1664 strlist_prepend(&preprocessor_flags, defflags[i]);
1665
1666 for (i = 0; i < (int)sizeof(gcppflags)/(int)sizeof(char *); i++)
1667 strlist_prepend(&preprocessor_flags, gcppflags[i]);
1668 strlist_prepend(&preprocessor_flags, xgnu89 ?
1669 "-D__GNUC_GNU_INLINE__" : "-D__GNUC_STDC_INLINE__");
1670
1671 cksetflags(cppflgcheck, &preprocessor_flags, 'p');
1672
1673 for (i = 0; i < (int)sizeof(fpflags)/(int)sizeof(char *); i++)
1674 strlist_prepend(&preprocessor_flags, fpflags[i]);
1675
1676 for (i = 0; cppadd[i]; i++)
1677 strlist_prepend(&preprocessor_flags, cppadd[i]);
1678 for (i = 0; cppmdadd[i]; i++)
1679 strlist_prepend(&preprocessor_flags, cppmdadd[i]);
1680
1681 /* Include dirs */
1682 strlist_append(&sysincdirs, "=" INCLUDEDIR "pcc/");
1683 #ifdef STDINC_MA
1684 strlist_append(&sysincdirs, "=" STDINC_MA);
1685 #endif
1686 strlist_append(&sysincdirs, "=" STDINC);
1687 #ifdef PCCINCDIR
1688 if (cxxflag)
1689 strlist_append(&sysincdirs, "=" PCCINCDIR "/c++");
1690 strlist_append(&sysincdirs, "=" PCCINCDIR);
1691 #endif
1692 }
1693
1694 struct flgcheck ccomflgcheck[] = {
1695 { &Oflag, 1, "-xtemps" },
1696 { &Oflag, 1, "-xdeljumps" },
1697 { &Oflag, 1, "-xinline" },
1698 { &Oflag, 1, "-xdce" },
1699 #ifdef notyet
1700 { &Oflag, 1, "-xssa" },
1701 #endif
1702 { &freestanding, 1, "-ffreestanding" },
1703 { &pgflag, 1, "-p" },
1704 { &gflag, 1, "-g" },
1705 { &xgnu89, 1, "-xgnu89" },
1706 { &xgnu99, 1, "-xgnu99" },
1707 { &xuchar, 1, "-xuchar" },
1708 #if !defined(os_sunos) && !defined(mach_i386)
1709 { &vflag, 1, "-v" },
1710 #endif
1711 #ifdef os_darwin
1712 { &Bstatic, 0, "-k" },
1713 #elif defined(os_sunos) && defined(mach_i386)
1714 { &kflag, 1, "-K" },
1715 { &kflag, 1, "pic" },
1716 #else
1717 { &kflag, 1, "-k" },
1718 #endif
1719 { &sspflag, 1, "-fstack-protector" },
1720 { 0 }
1721 };
1722
1723 void
setup_ccom_flags(void)1724 setup_ccom_flags(void)
1725 {
1726
1727 cksetflags(ccomflgcheck, &compiler_flags, 'a');
1728 }
1729
1730 static int one = 1;
1731
1732 struct flgcheck asflgcheck[] = {
1733 #if defined(USE_YASM)
1734 { &one, 1, "-p" },
1735 { &one, 1, "gnu" },
1736 { &one, 1, "-f" },
1737 #if defined(os_win32)
1738 { &one, 1, "win32" },
1739 #elif defined(os_darwin)
1740 { &one, 1, "macho" },
1741 #else
1742 { &one, 1, "elf" },
1743 #endif
1744 #endif
1745 #if defined(os_sunos) && defined(mach_sparc64)
1746 { &one, 1, "-m64" },
1747 #endif
1748 #if defined(os_darwin)
1749 { &Bstatic, 1, "-static" },
1750 #endif
1751 #if !defined(USE_YASM)
1752 { &vflag, 1, "-v" },
1753 #endif
1754 { &kflag, 1, "-k" },
1755 #ifdef os_darwin
1756 { &one, 1, "-arch" },
1757 #if mach_amd64
1758 { &amd64_i386, 1, "i386" },
1759 { &amd64_i386, 0, "x86_64" },
1760 #else
1761 { &one, 1, "i386" },
1762 #endif
1763 #else
1764 #ifdef mach_amd64
1765 { &amd64_i386, 1, "--32" },
1766 #endif
1767 #endif
1768 { 0 }
1769 };
1770 void
setup_as_flags(void)1771 setup_as_flags(void)
1772 {
1773 one = one;
1774 #ifdef PCC_SETUP_AS_ARGS
1775 PCC_SETUP_AS_ARGS
1776 #endif
1777 cksetflags(asflgcheck, &assembler_flags, 'a');
1778 }
1779
1780 struct flgcheck ldflgcheck[] = {
1781 #ifndef MSLINKER
1782 { &vflag, 1, "-v" },
1783 #endif
1784 #ifdef os_darwin
1785 { &shared, 1, "-dylib" },
1786 #elif defined(os_win32)
1787 { &shared, 1, "-Bdynamic" },
1788 #else
1789 { &shared, 1, "-shared" },
1790 #endif
1791 #if !defined(os_sunos) && !defined(os_win32)
1792 #ifndef os_darwin
1793 { &shared, 0, "-d" },
1794 #endif
1795 #endif
1796 #ifdef os_darwin
1797 { &Bstatic, 1, "-static" },
1798 #else
1799 { &Bstatic, 1, "-Bstatic" },
1800 #endif
1801 #if !defined(os_darwin) && !defined(os_sunos)
1802 { &gflag, 1, "-g" },
1803 #endif
1804 { &pthreads, 1, "-lpthread" },
1805 { 0 },
1806 };
1807
1808 static void
strap(struct strlist * sh,struct strlist * cd,char * n,int where)1809 strap(struct strlist *sh, struct strlist *cd, char *n, int where)
1810 {
1811 void (*fn)(struct strlist *, const char *);
1812 char *fil;
1813
1814 if (n == 0)
1815 return; /* no crtfile */
1816
1817 fn = where == 'p' ? strlist_prepend : strlist_append;
1818 fil = find_file(n, cd, R_OK);
1819 (*fn)(sh, fil);
1820 }
1821
1822 void
setup_ld_flags(void)1823 setup_ld_flags(void)
1824 {
1825 char *b, *e;
1826 int i;
1827
1828 cksetflags(ldflgcheck, &early_linker_flags, 'a');
1829 if (Bstatic == 0 && shared == 0 && rflag == 0) {
1830 for (i = 0; dynlinker[i]; i++)
1831 strlist_append(&early_linker_flags, dynlinker[i]);
1832 strlist_append(&early_linker_flags, "-e");
1833 strlist_append(&early_linker_flags, STARTLABEL);
1834 }
1835 if (shared == 0 && rflag)
1836 strlist_append(&early_linker_flags, "-r");
1837 if (sysroot && *sysroot)
1838 strlist_append(&early_linker_flags, cat("--sysroot=", sysroot));
1839 if (!nostdlib) {
1840 /* library search paths */
1841 if (pcclibdir)
1842 strlist_append(&late_linker_flags,
1843 cat("-L", pcclibdir));
1844 for (i = 0; deflibdirs[i]; i++)
1845 strlist_append(&late_linker_flags,
1846 cat("-L", deflibdirs[i]));
1847 /* standard libraries */
1848 if (pgflag) {
1849 for (i = 0; defproflibs[i]; i++)
1850 strlist_append(&late_linker_flags,
1851 defproflibs[i]);
1852 } else if (cxxflag) {
1853 for (i = 0; defcxxlibs[i]; i++)
1854 strlist_append(&late_linker_flags,
1855 defcxxlibs[i]);
1856 } else {
1857 for (i = 0; deflibs[i]; i++)
1858 strlist_append(&late_linker_flags, deflibs[i]);
1859 }
1860 }
1861 if (!nostartfiles) {
1862 if (Bstatic) {
1863 b = CRTBEGIN_T;
1864 e = CRTEND_T;
1865 } else if (shared /* || pieflag */) {
1866 b = CRTBEGIN_S;
1867 e = CRTEND_S;
1868 } else {
1869 b = CRTBEGIN;
1870 e = CRTEND;
1871 }
1872 strap(&middle_linker_flags, &crtdirs, b, 'p');
1873 strap(&late_linker_flags, &crtdirs, e, 'a');
1874 if (CRTI[0])
1875 strap(&middle_linker_flags, &crtdirs, CRTI, 'p');
1876 if (CRTN[0])
1877 strap(&late_linker_flags, &crtdirs, CRTN, 'a');
1878 if (shared == 0) {
1879 if (pgflag)
1880 b = GCRT0;
1881 #ifdef notyet
1882 else if (pieflag)
1883 b = SCRT0;
1884 #endif
1885 else
1886 b = CRT0;
1887 strap(&middle_linker_flags, &crtdirs, b, 'p');
1888 }
1889 }
1890 }
1891
1892 #ifdef os_win32
1893 char *
win32pathsubst(char * s)1894 win32pathsubst(char *s)
1895 {
1896 char env[1024];
1897 DWORD len;
1898
1899 len = ExpandEnvironmentStrings(s, env, sizeof(env));
1900 if (len == 0 || len > sizeof(env))
1901 errorx(8, "ExpandEnvironmentStrings failed, len %lu", len);
1902
1903 len--; /* skip nil */
1904 while (len-- > 0 && (env[len] == '/' || env[len] == '\\'))
1905 env[len] = '\0';
1906
1907 return xstrdup(env);
1908 }
1909
1910 char *
win32commandline(struct strlist * l)1911 win32commandline(struct strlist *l)
1912 {
1913 const struct string *s;
1914 char *cmd;
1915 char *p;
1916 int len;
1917 int j, k;
1918
1919 len = 0;
1920 STRLIST_FOREACH(s, l) {
1921 len++;
1922 for (j = 0; s->value[j] != '\0'; j++) {
1923 if (s->value[j] == '\"') {
1924 for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
1925 len++;
1926 len++;
1927 }
1928 len++;
1929 }
1930 for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
1931 len++;
1932 len++;
1933 len++;
1934 }
1935
1936 p = cmd = xmalloc(len);
1937
1938 STRLIST_FOREACH(s, l) {
1939 *p++ = '\"';
1940 for (j = 0; s->value[j] != '\0'; j++) {
1941 if (s->value[j] == '\"') {
1942 for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
1943 *p++ = '\\';
1944 *p++ = '\\';
1945 }
1946 *p++ = s->value[j];
1947 }
1948 for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
1949 *p++ = '\\';
1950 *p++ = '\"';
1951 *p++ = ' ';
1952 }
1953 p[-1] = '\0';
1954
1955 return cmd;
1956 }
1957 #endif
1958