/* * 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 #include #include #include #include #include #include #include #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 !!! */ }