/*
* 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.
*
* Driver for cpp, nasm, ncc and ld
*/
#include "driver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <assert.h>
#include "exectools.h"
#include "backend.h"
#include "misc.h"
#include "debug.h"
#include "cc_main.h"
#include "defs.h"
#include "n_libc.h"
/*
* Store file path referenced by ``name'' in dynamically allocated variable
* *output_names, resize it if necessary (*output_index contains the
* number of files in use, it is incremented at each call. The variable keeping
* track of allocated members in *output_names is static.)
*/
static int
store_file(char ***output_names, int **output_del, int needdel,
char *name, int *output_index) {
static int alloc = 0;
static int chunk_size = 8;
int tmpi = *output_index;
if (tmpi >= alloc) {
alloc += chunk_size;
/* Quadratically increase number of allocated slots */
chunk_size *= chunk_size;
*output_names =
n_xrealloc(*output_names, alloc * sizeof(char *));
*output_del =
n_xrealloc(*output_del, alloc * sizeof **output_del);
}
(*output_names)[tmpi] = n_xstrdup(name);
(*output_del)[tmpi] = needdel;
++(*output_index);
return 0;
}
extern int Sflag; /* XXX */
int
driver(char **cpp_flags, char *asm_flags, char *ld_flags, char **files) {
int i;
int rc;
int out_index = 0;
int ld_cmd_len;
int has_errors = 0;
char *ld_cmd;
char **output_names = NULL;
char buf[256];
int *output_del = NULL;
pid_t pid;
FILE *fd;
char ld_std_flags[512];
if (archflag == ARCH_X86) {
#if defined __FreeBSD__
strcpy(ld_std_flags,
"-dynamic-linker /usr/libexec/ld-elf.so.1 "
"/usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o "
"-L/usr/lib -lc /usr/lib/crtend.o /usr/lib/crtn.o ");
#elif defined __DragonFly__
/*
* Uses same flags as FreeBSD except for ld-elf.so.2 instead
* of ld-elf.so.1
*/
strcpy(ld_std_flags,
"-dynamic-linker /usr/libexec/ld-elf.so.2 "
"/usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o "
"-L/usr/lib -lc /usr/lib/crtend.o /usr/lib/crtn.o ");
#elif defined __OpenBSD__
strcpy(ld_std_flags,
"-e __start -Bdynamic -dynamic-linker "
"/usr/libexec/ld.so /usr/lib/crt0.o /usr/lib/crtbegin.o"
" -lc /usr/lib/crtend.o ");
#elif defined linux
strcpy(ld_std_flags,
"-lc /usr/lib/crt1.o /usr/lib/crti.o "
"/usr/lib/crtn.o /usr/lib/libc.so "
"--dynamic-linker /lib/ld-linux.so.2 ");
#elif defined __sun
strcpy(ld_std_flags,
"-L/usr/ccs/lib -L/usr/lib -Qy /usr/lib/crt1.o "
"/usr/lib/crti.o -lc /usr/lib/crtn.o ");
#else
#endif
} else if (archflag == ARCH_AMD64) {
#if defined linux
/*
* 08/08/07: Explicitly use lib64 instead of lib
* dirs, since some distributions seem to put 32bit
* files into plain lib dirs
*/
strcpy(ld_std_flags, "-lc /usr/lib64/crt1.o /usr/lib64/crti.o "
"/usr/lib64/crtn.o /usr/lib64/libc.so "
"--dynamic-linker /lib64/ld-linux-x86-64.so.2 ");
#elif defined __FreeBSD__
strcpy(ld_std_flags, "/usr/lib/crt1.o /usr/lib/crti.o "
"/usr/lib/crtbegin.o -L/usr/lib -lc /usr/lib/crtend.o "
"/usr/lib/crtn.o -dynamic-linker /libexec/ld-elf.so.1 ");
#elif defined __OpenBSD__
strcpy(ld_std_flags, "/usr/lib/crt0.o -Bdynamic "
"-dynamic-linker /usr/libexec/ld.so "
"/usr/lib/crtbegin.o -lc /usr/lib/crtend.o "
"-L/usr/lib ");
#else
/* XXX */
(void) fprintf(stderr, "This operating system isn't supported"
" on AMD64\n");
#endif
} else if (archflag == ARCH_MIPS) {
if (abiflag == ABI_MIPS_N64) {
strcpy(ld_std_flags,
"-64 /usr/lib64/mips3/crt1.o -L/usr/lib64/mips3 "
"-L/usr/lib64 -lc /usr/lib64/mips3/crtn.o ");
} else {
strcpy(ld_std_flags,
"/usr/lib32/crt1.o /usr/lib32/crtn.o "
"/usr/lib32/bpcrt.o -lc ");
}
} else if (archflag == ARCH_POWER) {
if (abiflag == ABI_POWER64) {
strcpy(ld_std_flags,
"-bpT:0x10000000 -bpD:0x20000000 -btextro -b64 "
"/lib/crt0_64.o -L/usr/lib -lc ");
} else {
strcpy(ld_std_flags,
"-bpT:0x10000000 -bpD:0x20000000 -btextro /lib/crt0.o -L/usr/lib -lc ");
}
} else if (archflag == ARCH_SPARC) {
#ifdef linux
strcpy(ld_std_flags, "-m elf64_sparc -Y P,/usr/lib64 "
"-dynamic-linker /lib64/ld-linux.so.2 "
"-L/lib64 -L/usr/lib64 /usr/lib64/crt1.o "
"/usr/lib64/crti.o /usr/lib64/crtn.o -lc ");
#else /* Solaris */
/*
* Because Solaris/SPARC does not ship with crt1.o, we
* use our own
*/
struct stat sbuf;
char *crt1 = NULL;
if (abiflag == ABI_SPARC64) {
if (stat(INSTALLDIR "/nwcc/lib/crt1-64.o", &sbuf)==0) {
crt1 = INSTALLDIR "/nwcc/lib/crt1-64.o";
} else if (stat("./crt1-64.o", &sbuf) == 0) {
crt1 = "./crt1-64.o";
}
} else {
/* 32bit */
if (stat(INSTALLDIR "/nwcc/lib/crt1-32.o", &sbuf)==0) {
crt1 = INSTALLDIR "/nwcc/lib/crt1-324.o";
} else if (stat("./crt1-32.o", &sbuf) == 0) {
crt1 = "./crt1-32.o";
}
}
if (crt1 == NULL) {
(void) fprintf(stderr, "Warning: No crt1 object found "
"in " INSTALLDIR "/nwcc/lib or .!\n");
crt1 = "";
}
if (abiflag == ABI_SPARC64) {
/*
* /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/crt1.o
/sparcv9/crt1.o*/
sprintf(ld_std_flags,
"/usr/lib/sparcv9/crti.o /usr/lib/sparcv9/crtn.o %s "
"-Y \"P,/usr/ccs/lib/sparcv9:/lib/sparcv9"
":/usr/lib/sparcv9\" -lc ",
crt1);
} else {
sprintf(ld_std_flags,
"/usr/lib/crti.o /usr/lib/crtn.o %s "
"-Y \"P,/usr/ccs/lib:/lib:/usr/lib\" -lc ",
crt1);
}
#endif
} else {
unimpl();
}
for (i = 0; files[i] != NULL; ++i) {
char *p = strrchr(files[i], '.');
char *p2;
int needdel = 1;
/* Ignore files without appropriate extension */
if (p == NULL) {
continue;
}
++p;
/*
* Determine file type to decide which tools (cpp, nasm, ld)
* have to be invoked.
*/
#if 0
if (assembler == ASM_GAS
|| archflag == ARCH_MIPS
|| archflag == ) {
#endif
{
/*
* gas doesn't do foo.c -> foo.o by default. It calls
* the output a.out. *barf*
* XXX This is kludged
*/
static char *out_ptr;
char *filep;
if ((filep = strrchr(files[i], '/')) != NULL) {
++filep;
} else {
filep = files[i];
}
if (!cflag || !oflag) {
if (out_ptr == NULL) {
out_ptr = strchr(asm_flags, 0);
}
sprintf(out_ptr, " -o %.*s.o",
(int)(p - filep - 1), filep);
}
}
#if 0
}
#endif
if (strcmp(p, "c") == 0 || strcmp(p, "i") == 0) {
p2 = files[i];
#ifdef DEBUG
printf("Preprocessed successfully as %s\n", p2);
#endif
/* Compile file ``p2''. */
if ((pid = fork()) == -1) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pid == 0) {
char *nwcc1_args[256]; /* XXX */
char *arch = NULL;
int j = 0;
int k = 0;
nwcc1_args[j++] = "nwcc1";
if (stackprotectflag) {
nwcc1_args[j++] = "-stackprotect";
}
if (gnuc_version) {
static char gnubuf[128];
sprintf(gnubuf, "-gnuc=%s",
gnuc_version);
nwcc1_args[j++] = gnubuf;
}
if (ansiflag) {
nwcc1_args[j++] = "-ansi";
}
if (pedanticflag) {
nwcc1_args[j++] = "-pedantic";
}
if (nostdinc_flag) {
nwcc1_args[j++] = "-nostdinc";
}
if (gflag) {
nwcc1_args[j++] = "-g";
}
if (Eflag) {
nwcc1_args[j++] = "-E";
}
switch (archflag) {
case ARCH_X86:
arch = "-arch=x86";
break;
case ARCH_AMD64:
arch = "-arch=amd64";
break;
case ARCH_POWER:
arch = "-arch=ppc";
break;
case ARCH_MIPS:
arch = "-arch=mips";
break;
case ARCH_SPARC:
arch = "-arch=sparc";
break;
case ARCH_PA:
case ARCH_ARM:
case ARCH_SH:
unimpl();
}
nwcc1_args[j++] = arch;
if (abiflag != abiflag_default) {
#if 0
switch (abiflag) {
case ABI_POWER32:
abi = "-mabi=aix32";
break;
case ABI_POWER64:
abi = "-mabi=aix64";
break;
case ABI_MIPS_N32:
abi = "-mabi=n32";
break;
case ABI_MIPS_N64:
abi = "-mabi=n64";
break;
case 0:
break;
default:
unimpl();
}
if (abi != NULL) {
#endif
if (abiflag != 0) {
nwcc1_args[j++] = /*abi*/
abi_to_option(abiflag);
}
}
if (asmflag) {
nwcc1_args[j] =
n_xmalloc(strlen(asmflag)+16);
sprintf(nwcc1_args[j++],
"-asm=%s", asmflag);
}
nwcc1_args[j++] = p2;
for (; cpp_flags[k] != NULL; ++j, ++k) {
nwcc1_args[j] = cpp_flags[k];
}
nwcc1_args[j] = NULL;
#define DEVEL
#ifdef DEVEL
execv("./nwcc1", nwcc1_args);
#endif
if ((p = getenv("NWCC_CC1")) != NULL) {
execv(p, nwcc1_args);
perror(p);
} else {
#if 0
execv("/usr/local/bin/nwcc1",
nwcc1_args);
perror("/usr/local/bin/nwcc1");
#endif
execv(INSTALLDIR "/bin/nwcc1",
nwcc1_args);
perror(INSTALLDIR "/bin/nwcc1");
}
exit(EXIT_FAILURE);
} else {
if (waitpid(pid, &rc, 0) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (rc != 0) {
/* Try other files anyway */
has_errors = 1;
continue;
}
}
/*
* nwcc just outputs with the same name as the input,
* except that the ending is .asm instead of .cpp
*/
#ifdef DEBUG
printf("Compiled successfully as %s\n", p2);
#endif
if (Sflag || Eflag) {
continue;
}
p = p2;
p2 = n_xmalloc(strlen(p2) + sizeof ".asm");
strcpy(p2, p);
p = strrchr(p2, '.');
strcpy(++p, "asm");
/* Hopefully p2 is a valid .asm file now... */
if ((p = strrchr(p2, '/')) != NULL) {
char *saved = p+1;
p2 = do_asm(p+1, asm_flags, abiflag);
remove(saved);
} else {
char *saved_p2 = p2;
p2 = do_asm(p2, asm_flags, abiflag);
remove(saved_p2);
}
if (p2 == NULL) {
/* Ignore failure, try other files anyway. */
continue;
}
#ifdef DEBUG
printf("Assembled successfully as %s\n", p2);
#endif
} else if (strcmp(p, "asm") == 0) {
p2 = do_asm(files[i], asm_flags, abiflag);
if (p2 == NULL) {
/* Ignore failure, try other files anyway. */
continue;
}
} else if (strcmp(p, "o") == 0
|| strcmp(p, "a") == 0
|| strcmp(p, "so") == 0) {
/*
* Don't do anything, the name is later just
* stored for ld because it is an object,
* library archive or shared library file
*/
p2 = files[i];
needdel = 0;
} else {
continue;
}
/*
* File ought to be compiled and assembled fine. Store path for
* later ld invocation
*/
if (store_file(&output_names, &output_del,
needdel, p2, &out_index) != 0) {
fprintf(stderr, "Exiting.\n");
return 1;
}
}
if (i == 0) {
fprintf(stderr, "Missing input files.\n");
return 1;
}
if (cflag || Sflag || Eflag) return has_errors;
if (output_names == NULL) {
fprintf(stderr, "No valid files to link.\n");
return 1;
}
/* Count length of all files plus white spaces and ld flags */
ld_cmd_len = 0;
for (i = 0; i < out_index; ++i) {
ld_cmd_len += strlen(output_names[i]);
++ld_cmd_len; /* white space */
}
ld_cmd_len += strlen(ld_flags);
ld_cmd = malloc(sizeof "ld " + ld_cmd_len + 1 + sizeof ld_std_flags);
if (ld_cmd == NULL) {
perror("malloc");
return 1;
}
if (archflag == ARCH_SPARC) {
#ifdef linux
strcpy(ld_cmd, "ld ");
#else
/* Solaris */
if (abiflag == ABI_SPARC64) {
strcpy(ld_cmd, "/usr/ccs/bin/sparcv9/ld ");
} else {
strcpy(ld_cmd, "/usr/ccs/bin/ld ");
}
#endif
} else {
strcpy(ld_cmd, "ld ");
}
for (i = 0; i < out_index; ++i) {
strcat(ld_cmd, output_names[i]);
strcat(ld_cmd, " ");
}
strcat(ld_cmd, ld_std_flags);
strcat(ld_cmd, ld_flags);
#if 0
printf("Executing %s\n", ld_cmd);
#endif
fd = popen(ld_cmd, "r");
if (fd == NULL) {
perror("popen");
return 1;
}
while (fgets(buf, sizeof buf, fd)) {
printf("%s", buf);
}
for (i = 0; i < out_index; ++i) {
if (output_del[i]) {
remove(output_names[i]);
}
}
rc = pclose(fd);
if (WIFEXITED(rc)) {
rc = WEXITSTATUS(rc);
if (rc != 0) {
has_errors = 1;
} else {
if (sflag) {
/*
* Strip. Note that this is only done here;
* i.e. when building an executable file.
* When doing ``nwcc -c foo.c -s'', the
* flag is silently ignored, just like in
* gcc
*/
if ((fd = exec_cmd("strip", " %s", out_file)) != NULL) {
rc = pclose(fd);
if (!WIFEXITED(rc)
|| WEXITSTATUS(rc) != 0) {
has_errors = 1;
}
} else {
has_errors = 1;
}
}
}
} else {
has_errors = 1;
}
return has_errors /*|| ((unsigned)pclose(fd) >> 8)*/ ; /* XXX !!! */
}
syntax highlighted by Code2HTML, v. 0.9.1