/*
* Copyright (c) 2003 - 2007, Nils R. Weller
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* nwcc compiler driver
*/
#include "cc_main.h"
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "driver.h"
#include "error.h"
#include "defs.h"
#include "debug.h"
#include "backend.h"
#include "misc.h"
#include "cfgfile.h"
#include "n_libc.h"
int Sflag;
int sflag;
int Eflag;
int cflag;
int oflag;
int gflag;
int assembler;
int stackprotectflag;
int gnuheadersflag = 1; /* XXX */
int pedanticflag;
int ansiflag;
char *asmflag;
char *gnuc_version;
int archflag;
int abiflag;
int abiflag_default;
int nostdinc_flag;
char *out_file = "a.out";
static void
usage(void) {
/* XXX add useful stuff here */
puts("You invoked nwcc incorrectly. Please refer to the README file");
puts("for supported command line arguments");
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[]) {
int ch;
int i;
int ldind = 0;
int idx;
int nolibnwccflag = 0;
size_t ldpos = 0;
size_t ldalloc = 0;
size_t cppind = 0;
char asm_flags[1024];
char *asm_cmdline = NULL;
char *ld_flags = NULL;
char *ld_args[128];
char *cpp_args[128];
char *ld_cmdline = NULL;
char *target_str = NULL;
char *abi_str = NULL;
struct stat sbuf;
struct cfg_option *cfg_file_options;
struct ga_option options[] = {
{ 'D', NULL, 1 },
{ 'U', NULL, 1 },
{ 'I', NULL, 1 },
{ 'l', NULL, 1 },
{ 'L', NULL, 1 },
{ 'o', NULL, 1 },
{ 'n', NULL, 1 },
{ 'S', NULL, 0 },
{ 'E', NULL, 0 },
{ 'c', NULL, 0 },
{ 'W', NULL, 0 }, /* ignore */
{ 'f', NULL, 0 }, /* ignore */
{ 'g', NULL, 0 }, /* ignore */
{ 'm', NULL, 0 }, /* ignore */
{ 'O', NULL, 0 }, /* ignore */
{ 's', NULL, 0 }, /* strip */
{ 0, "verboseoffsets", 0 },
{ 0, "stackprotect", 0 },
{ 0, "nolibnwcc", 0 },
{ 0, "pthread", 0 }, /* ignore */
{ 0, "print-prog-name", 1 },
{ 0, "nostdinc", 0 },
{ 0, "rdynamic", 0 }, /* ignore */
{ 0, "static", 0 }, /* ignore (this hurts, we need it!) */
{ 0, "export-dynamic", 0 }, /* ignore */
{ 0, "arch", 1 },
{ 0, "gnuc", 1 },
#ifdef __sun
{ 0, "xarch", 1 },
#endif
{ 0, "O0", 0 }, /* ignore */
{ 0, "O1", 0 }, /* ignore */
{ 0, "O2", 0 }, /* ignore */
{ 0, "O3", 0 }, /* ignore */
{ 0, "ggdb", 0 }, /* ignore */
{ 0, "Wall", 0 }, /* ignore */
{ 0, "pedantic", 0 }, /* ignore */
{ 0, "version", 0 },
{ 0, "pg", 0 }, /* ignore */
{ 0, "pipe", 0 }, /* ignore */
{ 0, "ansi", 0 },
{ 0, "std", 0 },
{ 0, "mabi", 1 },
{ 0, "maix64", 0 },
{ 0, "abi", 1 },
{ 0, "asm", 1 }
};
int nopts = N_OPTIONS(options);
if ((cfg_file_options = read_config_files()) != NULL) {
/*
* There are config files that need to be integrated into
* the command line
*/
char **tmpargv;
int tmpargc = argc;
tmpargv = make_new_argv(argv, &tmpargc, cfg_file_options,
options, nopts);
if (tmpargv != NULL) {
argv = tmpargv;
argc = tmpargc;
}
}
while ((ch = nw_get_arg(argc-1, argv+1, options, nopts, &idx)) != -1) {
switch (ch) {
case 'n':
asm_cmdline = n_xstrdup(n_optarg);
break;
case 'c':
cflag = 1;
break;
case 's':
sflag = 1;
break;
case 'I':
case 'D':
case 'U':
if (cppind == 126) {
(void) fprintf(stderr,
"Too many cpp flags\n");
return 1;
}
if (ch == 'I') {
cpp_args[cppind++] = "-I";
} else if (ch == 'D') {
cpp_args[cppind++] = "-D";
} else if (ch == 'U') {
cpp_args[cppind++] = "-U";
}
cpp_args[cppind++] = n_optarg;
break;
case 'E':
Eflag = 1;
break;
case 'l':
case 'L':
if (ldind == 126) {
(void) fprintf(stderr,
"Too many linker flags\n");
return 1;
}
if (ch == 'l') {
ld_args[ldind++] = "-l";
} else if (ch == 'L') {
ld_args[ldind++] = "-L";
}
ld_args[ldind++] = n_optarg;
break;
case 'o':
out_file = n_xstrdup(n_optarg);
oflag = 1;
break;
case 'S':
Sflag = 1;
break;
case 'O':
case 'W': /* Ignore -W/-O */
break;
case 'g':
gflag = 1;
break;
case '!':
break;
case '?':
if (idx) {
if (strcmp(options[idx].name, "stackprotect")
== 0) {
stackprotectflag = 1;
} else if (strcmp(options[idx].name,
"nolibnwcc") == 0) {
nolibnwccflag = 1;
} else if (strcmp(options[idx].name, "Wall")
== 0) {
; /* Ignore */
} else if (options[idx].name[0] == 'O'
&& isdigit(options[idx].name[1])) {
; /* Ignore */
} else if (strcmp(options[idx].name, "ggdb")
== 0) {
; /* Ignore */
} else if (strcmp(options[idx].name, "ansi")
== 0) {
ansiflag = 1;
} else if (strcmp(options[idx].name, "std")
== 0) {
;
} else if (strcmp(options[idx].name, "pg")
== 0) {
; /* Ignore */
} else if (strcmp(options[idx].name, "pedantic")
== 0) {
pedanticflag = 1;
} else if (strcmp(options[idx].name, "pipe")
== 0) {
; /* Ignore */
} else if (strcmp(options[idx].name, "pthread")
== 0) {
ld_args[ldind++] =
"-lpthread";
} else if (strcmp(options[idx].name, "rdynamic")
== 0) {
(void) fprintf(stderr, "Warning: "
"-rdynamic is ignored\n");
} else if (strcmp(options[idx].name, "export-dynamic")
== 0) {
(void) fprintf(stderr, "Warning: "
"-export-dynamic is ignored\n");
} else if (strcmp(options[idx].name,
"nostdinc") == 0) {
nostdinc_flag = 1;
} else if (strcmp(options[idx].name, "asm")
== 0) {
if (asmflag) {
(void) fprintf(stderr, "-asm "
"used more than once\n");
exit(EXIT_FAILURE);
}
asmflag = n_xstrdup(n_optarg);
} else if (strcmp(options[idx].name, "arch")
== 0) {
if (target_str != NULL) {
(void) fprintf(stderr, "-arch "
"used more than once\n");
exit(EXIT_FAILURE);
}
target_str = n_xstrdup(n_optarg);
} else if (strcmp(options[idx].name, "static")
== 0) {
(void) fprintf(stderr, "Warning: "
"ignoring -static option\n");
} else if (strcmp(options[idx].name, "gnuc")
== 0) {
if (gnuc_version != NULL) {
(void) fprintf(stderr, "-gnuc "
"used more than once\n");
exit(EXIT_FAILURE);
} else if (strlen(n_optarg) > 10) {
(void) fprintf(stderr, "Bogus "
"argument to -gnuc\n");
exit(EXIT_FAILURE);
}
gnuc_version = n_xstrdup(n_optarg);
} else if (strcmp(options[idx].name, "xarch")
== 0) {
;
} else if (strcmp(options[idx].name,
"print-prog-name") == 0) {
char buf[2048];
if (find_cmd(n_optarg, buf, sizeof buf)
== -1) {
puts(n_optarg);
} else {
puts(buf);
}
exit(0);
} else if (strcmp(options[idx].name, "maix64")
== 0) {
abi_str = n_xstrdup("aix64"); /* XXX */
} else if (strcmp(options[idx].name, "mabi")
== 0
|| strcmp(options[idx].name, "abi")
== 0) {
if (abi_str != NULL) {
(void) fprintf(stderr, "-mabi "
"used more than once");
exit(EXIT_FAILURE);
}
abi_str = n_xstrdup(n_optarg);
} else if (strcmp(options[idx].name, "version")
== 0) {
printf("nwcc %s\n", NWCC_VERSION);
printf("Copyright (c) 2003 - 2007 "
"Nils Robert Weller\n");
exit(0);
} else {
usage();
}
} else {
usage();
}
break;
default:
usage();
}
}
cpp_args[cppind] = NULL;
set_target_arch_and_abi(&archflag, &abiflag, target_str, abi_str);
if (target_str != NULL) {
int hostarch;
int hostabi;
get_host_arch(&hostarch, &hostabi);
if (archflag != hostarch && !Sflag) {
(void) fprintf(stderr, "Warning: Cross-compilation "
"implies -S (only generates *.asm file.)\n");
Sflag = 1;
}
}
#if 0
if (sizeof(long) == 8 && archflag == ARCH_POWER) {
abiflag = ABI_POWER64;
}
#endif
/*
* libnwcc is now linked statically because there isn't
* a whole lot of code in it anyway
*/
if (!nolibnwccflag) {
int is_64bit =
abiflag == ABI_POWER64
|| abiflag == ABI_MIPS_N64
|| abiflag == ABI_SPARC64;
if (is_64bit) {
if (stat(INSTALLDIR "/lib/libnwcc64.o", &sbuf) != -1) {
ld_args[ldind++] = INSTALLDIR "/lib/libnwcc64.o";
} else if (stat("./extlibnwcc64.o", &sbuf) != -1) {
ld_args[ldind++] = "./extlibnwcc64.o";
} else if (stat(INSTALLDIR "/lib/libnwcc.o", &sbuf) != -1) {
ld_args[ldind++] = INSTALLDIR "/lib/libnwcc.o";
} else if (stat(INSTALLDIR "./extlibnwcc.o", &sbuf) != -1) {
ld_args[ldind++] = INSTALLDIR "./extlibnwcc.o";
}
} else {
if (stat(INSTALLDIR "/lib/libnwcc32.o", &sbuf) != -1) {
ld_args[ldind++] = INSTALLDIR "/lib/libnwcc32.o";
} else if (stat("./extlibnwcc32.o", &sbuf) != -1) {
ld_args[ldind++] = "./extlibnwcc32.o";
} else if (stat(INSTALLDIR "/lib/libnwcc.o", &sbuf) != -1) {
ld_args[ldind++] = INSTALLDIR "/lib/libnwcc.o";
} else if (stat("./extlibnwcc.o", &sbuf) != -1) {
ld_args[ldind++] = "./extlibnwcc.o";
}
}
#if 0
if (is_64bit) {
if (stat("/usr/local/lib/libnwcc64.o", &sbuf) != -1) {
ld_args[ldind++] = "/usr/local/lib/libnwcc64.o";
} else if (stat("./extlibnwcc64.o", &sbuf) != -1) {
ld_args[ldind++] = "./extlibnwcc64.o";
}
} else {
if (stat("/usr/local/lib/libnwcc.o", &sbuf) != -1) {
ld_args[ldind++] = "/usr/local/lib/libnwcc.o";
} else if (stat("./extlibnwcc.o", &sbuf) != -1) {
ld_args[ldind++] = "./extlibnwcc.o";
}
}
#endif
#ifdef __sgi
/* XXX otherwise symbols of libnwcc are unresolved */
ld_args[ldind++] = "-lc";
#endif
}
if (asmflag == NULL) {
asmflag = getenv("NWCC_ASM");
}
#if 0
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
asmflag = n_xstrdup("gas");
#endif
#ifdef __i386__
# if defined __sun
asmflag = n_xstrdup("gas");
assembler = ASM_GAS;
strcpy(asm_flags, "--traditional-format -Qy ");
# elif defined __FreeBSD__ || defined __OpenBSD__ || defined linux \
|| defined __DragonFly__
#if 0
if (asmflag == NULL) {
asmflag = n_xstrdup("gas");
}
#endif
if (asmflag == NULL) {
/*
* 07/28/07: Finally gas is the default assembler!
* This is meant to speed up assembling significantly
*/
assembler = ASM_GAS /*NASM*/;
asmflag = "gas";
*asm_flags = 0;
} else if (
strcmp(asmflag, "nasm") == 0
|| strcmp(asmflag, "nwasm") == 0
|| strcmp(asmflag, "yasm") == 0) {
if (strcmp(asmflag, "nwasm") == 0) {
assembler = ASM_NWASM;
} else {
assembler = *asmflag == 'n'? ASM_NASM: ASM_YASM;
}
strcpy(asm_flags, "-f elf ");
if (assembler == ASM_NWASM) {
/*
* Disable verbose output
*/
strcat(asm_flags, "-q ");
}
} else if (strcmp(asmflag, "gas") == 0
|| strcmp(asmflag, "as") == 0) {
assembler = ASM_GAS;
*asm_flags = 0;
} else {
(void) fprintf(stderr, "Unknown assembler `%s'\n", asmflag);
}
#elif defined __sun
# else
# error "Unsupported system (currently only Linux/FreeBSD/OpenBSD on x86 \
are supported)"
# endif
#elif defined __amd64__ || defined __x86_64__
if (asmflag == NULL) {
/*
* 07/28/07: Finally gas is the default assembler!
* This is meant to speed up assembling significantly
*/
asmflag = "gas";
assembler = ASM_GAS /*NASM*/;
*asm_flags = 0;
} else if (
strcmp(asmflag, "yasm") == 0) {
assembler = ASM_YASM; /* XXX */
strcpy(asm_flags, "-f elf -m amd64");
} else if (strcmp(asmflag, "gas") == 0
|| strcmp(asmflag, "as") == 0) {
assembler = ASM_GAS;
*asm_flags = 0;
} else {
(void) fprintf(stderr, "Unknown assembler `%s'\n", asmflag);
}
#elif defined __sgi
assembler = ASM_SGI_AS; /* XXX */
if (abiflag == ABI_MIPS_N64) {
strcpy(asm_flags, "-pic2 -elf -EB -O0 -g0 -G0 -w -mips3 "
"-64 -t5_ll_sc_bug ");
} else {
strcpy(asm_flags, "-pic2 -elf -EB -O0 -g0 -G0 -w -mips3 "
"-n32 -t5_ll_sc_bug ");
}
#elif defined __sun || defined __sparc
if (abiflag == ABI_SPARC64) {
#ifndef linux
strcpy(asm_flags, "-xarch=v9 ");
#else
strcpy(asm_flags, "--64 -Av9a -Qy ");
#endif
}
#elif defined _AIX
#if 0
strcpy(asm_flags, "-u -mcom ");
#endif
if (abiflag == ABI_POWER64) {
strcpy(asm_flags, "-u -many -a64 -mppc64");
} else {
strcpy(asm_flags, "-u -many");
}
#else
#error "Unsupported host architecture"
#endif
if (asm_cmdline != NULL) {
strncat(asm_flags, asm_cmdline,
sizeof asm_flags-strlen(asm_flags));
}
if (cflag && oflag) {
/* nwcc -c foo.c -o foo.o */
/* XXX */
sprintf(asm_flags+strlen(asm_flags), " -o %s", out_file);
}
make_room(&ld_flags, &ldalloc, sizeof "-o" + strlen(out_file));
ldpos += sprintf(ld_flags, "-o %s", out_file);
for (i = 0; i < ldind; ++i) {
make_room(&ld_flags, &ldalloc,
ldpos + strlen(ld_args[i]) + 2);
ldpos += sprintf(ld_flags+ldpos, " %s", ld_args[i]);
}
if (asm_cmdline) {
free(asm_cmdline);
}
if (ld_cmdline) {
free(ld_cmdline);
}
return driver(cpp_args, asm_flags, ld_flags, argv+1);
#if 0
- finish n64 on mips (self-compilation?)
todo:
- -ansi/-pedantic (warn about gnu features)
- for () variarble declarations
- stupid "c++ class style" scope bug
- check the "const int" snippet in log, and the tinycc
bugs before that
- check const correctnes.s.. char ** vs const char **
- fix initializer array/struct type problems once and for all!!!
(see mips initializer output o rwhatever that was)
- take a peek at gxemul (groan)
- x86 stack allocation bug (update sp before use)
- bitfields
- diagnostic void<->funcptr
- clean up builtins..mips should use x86? that amd64 sysv style
stuff should be reused for e.g. sysv on ppc
- floating point values in variadic funcs on amd64
#endif
}
syntax highlighted by Code2HTML, v. 0.9.1