Exemple #1
0
// Split a path into an Array of paths
Strings *FileName::splitPath(const char *path)
{
    char c = 0;                         // unnecessary initializer is for VC /W4
    const char *p;
    OutBuffer buf;
    Strings *array;

    array = new Strings();
    if (path)
    {
        p = path;
        do
        {   char instring = 0;

            while (isspace((utf8_t)*p))         // skip leading whitespace
                p++;
            buf.reserve(strlen(p) + 1); // guess size of path
            for (; ; p++)
            {
                c = *p;
                switch (c)
                {
                    case '"':
                        instring ^= 1;  // toggle inside/outside of string
                        continue;

#if MACINTOSH
                    case ',':
#endif
#if _WIN32
                    case ';':
#endif
#if POSIX
                    case ':':
#endif
                        p++;
                        break;          // note that ; cannot appear as part
                                        // of a path, quotes won't protect it

                    case 0x1A:          // ^Z means end of file
                    case 0:
                        break;

                    case '\r':
                        continue;       // ignore carriage returns

#if POSIX
                    case '~':
                        buf.writestring(getenv("HOME"));
                        continue;
#endif

#if 0
                    case ' ':
                    case '\t':          // tabs in filenames?
                        if (!instring)  // if not in string
                            break;      // treat as end of path
#endif
                    default:
                        buf.writeByte(c);
                        continue;
                }
                break;
            }
            if (buf.offset)             // if path is not empty
            {
                buf.writeByte(0);       // to asciiz
                array->push(buf.extractData());
            }
        } while (c);
    }
    return array;
}
Exemple #2
0
void getenv_setargv(const char *envvar, int *pargc, char** *pargv)
{
    char *p;

    int instring;
    int slash;
    char c;

    char *env = getenv(envvar);
    if (!env)
        return;

    env = mem.strdup(env);      // create our own writable copy

    int argc = *pargc;
    Strings *argv = new Strings();
    argv->setDim(argc);

    int argc_left = 0;
    for (int i = 0; i < argc; i++) {
        if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) {
            // HACK: set flag to indicate we saw '-run' here
            global.params.run = true;
            // Don't eat -run yet so the program arguments don't get changed
            argc_left = argc - i;
            argc = i;
            *pargv = &(*pargv)[i];
            argv->setDim(i);
            break;
        } else {
        }
    }
    // HACK to stop required values from command line being drawn from DFLAGS
    argv->push((char*)"");
    argc++;

    size_t j = 1;               // leave argv[0] alone
    while (1)
    {
        int wildcard = 1;       // do wildcard expansion
        switch (*env)
        {
            case ' ':
            case '\t':
                env++;
                break;

            case 0:
                goto Ldone;

            case '"':
                wildcard = 0;
            default:
                argv->push(env);                // append
                //argv->insert(j, env);         // insert at position j
                j++;
                argc++;
                p = env;
                slash = 0;
                instring = 0;
                c = 0;

                while (1)
                {
                    c = *env++;
                    switch (c)
                    {
                        case '"':
                            p -= (slash >> 1);
                            if (slash & 1)
                            {   p--;
                                goto Laddc;
                            }
                            instring ^= 1;
                            slash = 0;
                            continue;

                        case ' ':
                        case '\t':
                            if (instring)
                                goto Laddc;
                            *p = 0;
                            //if (wildcard)
                                //wildcardexpand();     // not implemented
                            break;

                        case '\\':
                            slash++;
                            *p++ = c;
                            continue;

                        case 0:
                            *p = 0;
                            //if (wildcard)
                                //wildcardexpand();     // not implemented
                            goto Ldone;

                        default:
                        Laddc:
                            slash = 0;
                            *p++ = c;
                            continue;
                    }
                    break;
                }
        }
    }

Ldone:
    assert(argc == argv->dim);
    argv->reserve(argc_left);
    for (int i = 0; i < argc_left; i++)
        argv->data[argc++] = (void *)(*pargv)[i];

    *pargc = argc;
    *pargv = argv->tdata();
}
Exemple #3
0
int runProgram()
{
    //printf("runProgram()\n");
    if (global.params.verbose)
    {
        printf("%s", global.params.exefile);
        for (size_t i = 0; i < global.params.runargs_length; i++)
            printf(" %s", (char *)global.params.runargs[i]);
        printf("\n");
    }

    // Build argv[]
    Strings argv;

    argv.push(global.params.exefile);
    for (size_t i = 0; i < global.params.runargs_length; i++)
    {   char *a = global.params.runargs[i];

#if _WIN32
        // BUG: what about " appearing in the string?
        if (strchr(a, ' '))
        {   char *b = (char *)mem.malloc(3 + strlen(a));
            sprintf(b, "\"%s\"", a);
            a = b;
        }
#endif
        argv.push(a);
    }
    argv.push(NULL);

#if _WIN32
    char *ex = FileName::name(global.params.exefile);
    if (ex == global.params.exefile)
        ex = FileName::combine(".", ex);
    else
        ex = global.params.exefile;
    return spawnv(0,ex,argv.tdata());
#elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
    pid_t childpid;
    int status;

    childpid = fork();
    if (childpid == 0)
    {
        char *fn = argv.tdata()[0];
        if (!FileName::absolute(fn))
        {   // Make it "./fn"
            fn = FileName::combine(".", fn);
        }
        execv(fn, argv.tdata());
        perror(fn);             // failed to execute
        return -1;
    }

    waitpid(childpid, &status, 0);

    if (WIFEXITED(status))
    {
        status = WEXITSTATUS(status);
        //printf("--- errorlevel %d\n", status);
    }
    else if (WIFSIGNALED(status))
    {
        printf("--- killed by signal %d\n", WTERMSIG(status));
        status = 1;
    }
    return status;
#else
    assert(0);
#endif
}
Exemple #4
0
int runLINK()
{
#if _WIN32
    char *p;
    int status;
    OutBuffer cmdbuf;

    global.params.libfiles->push("user32");
    global.params.libfiles->push("kernel32");

    for (size_t i = 0; i < global.params.objfiles->dim; i++)
    {
        if (i)
            cmdbuf.writeByte('+');
        p = global.params.objfiles->tdata()[i];
        char *basename = FileName::removeExt(FileName::name(p));
        char *ext = FileName::ext(p);
        if (ext && !strchr(basename, '.'))
            // Write name sans extension (but not if a double extension)
            writeFilename(&cmdbuf, p, ext - p - 1);
        else
            writeFilename(&cmdbuf, p);
        mem.free(basename);
    }
    cmdbuf.writeByte(',');
    if (global.params.exefile)
        writeFilename(&cmdbuf, global.params.exefile);
    else
    {   /* Generate exe file name from first obj name.
         * No need to add it to cmdbuf because the linker will default to it.
         */
        char *n = global.params.objfiles->tdata()[0];
        n = FileName::name(n);
        FileName *fn = FileName::forceExt(n, "exe");
        global.params.exefile = fn->toChars();
    }

    // Make sure path to exe file exists
    {   char *p = FileName::path(global.params.exefile);
        FileName::ensurePathExists(p);
        mem.free(p);
    }

    cmdbuf.writeByte(',');
    if (global.params.mapfile)
        writeFilename(&cmdbuf, global.params.mapfile);
    else if (global.params.map)
    {
        FileName *fn = FileName::forceExt(global.params.exefile, "map");

        char *path = FileName::path(global.params.exefile);
        char *p;
        if (path[0] == '\0')
            p = FileName::combine(global.params.objdir, fn->toChars());
        else
            p = fn->toChars();

        writeFilename(&cmdbuf, p);
    }
    else
        cmdbuf.writestring("nul");
    cmdbuf.writeByte(',');

    for (size_t i = 0; i < global.params.libfiles->dim; i++)
    {
        if (i)
            cmdbuf.writeByte('+');
        writeFilename(&cmdbuf, global.params.libfiles->tdata()[i]);
    }

    if (global.params.deffile)
    {
        cmdbuf.writeByte(',');
        writeFilename(&cmdbuf, global.params.deffile);
    }

    /* Eliminate unnecessary trailing commas    */
    while (1)
    {   size_t i = cmdbuf.offset;
        if (!i || cmdbuf.data[i - 1] != ',')
            break;
        cmdbuf.offset--;
    }

    if (global.params.resfile)
    {
        cmdbuf.writestring("/RC:");
        writeFilename(&cmdbuf, global.params.resfile);
    }

    if (global.params.map || global.params.mapfile)
        cmdbuf.writestring("/m");

#if 0
    if (debuginfo)
        cmdbuf.writestring("/li");
    if (codeview)
    {
        cmdbuf.writestring("/co");
        if (codeview3)
            cmdbuf.writestring(":3");
    }
#else
    if (global.params.symdebug)
        cmdbuf.writestring("/co");
#endif

    cmdbuf.writestring("/noi");
    for (size_t i = 0; i < global.params.linkswitches->dim; i++)
    {
        cmdbuf.writestring(global.params.linkswitches->tdata()[i]);
    }
    cmdbuf.writeByte(';');

    p = cmdbuf.toChars();

    FileName *lnkfilename = NULL;
    size_t plen = strlen(p);
    if (plen > 7000)
    {
        lnkfilename = FileName::forceExt(global.params.exefile, "lnk");
        File flnk(lnkfilename);
        flnk.setbuffer(p, plen);
        flnk.ref = 1;
        if (flnk.write())
            error(0, "error writing file %s", lnkfilename);
        if (lnkfilename->len() < plen)
            sprintf(p, "@%s", lnkfilename->toChars());
    }

    char *linkcmd = getenv("LINKCMD");
    if (!linkcmd)
        linkcmd = "link";
    status = executecmd(linkcmd, p, 1);
    if (lnkfilename)
    {
        remove(lnkfilename->toChars());
        delete lnkfilename;
    }
    return status;
#elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
    pid_t childpid;
    int i;
    int status;

    // Build argv[]
    Strings argv;

    const char *cc = getenv("CC");
    if (!cc)
        cc = "gcc";
    argv.push((char *)cc);
    argv.insert(1, global.params.objfiles);

#if __APPLE__
    // If we are on Mac OS X and linking a dynamic library,
    // add the "-dynamiclib" flag
    if (global.params.dll)
        argv.push((char *) "-dynamiclib");
#elif linux || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
    if (global.params.dll)
        argv.push((char *) "-shared");
#endif

    // None of that a.out stuff. Use explicit exe file name, or
    // generate one from name of first source file.
    argv.push((char *)"-o");
    if (global.params.exefile)
    {
        if (global.params.dll)
            global.params.exefile = FileName::forceExt(global.params.exefile, global.dll_ext)->toChars();
        argv.push(global.params.exefile);
    }
    else
    {   // Generate exe file name from first obj name
        char *n = global.params.objfiles->tdata()[0];
        char *e;
        char *ex;

        n = FileName::name(n);
        e = FileName::ext(n);
        if (e)
        {
            e--;                        // back up over '.'
            ex = (char *)mem.malloc(e - n + 1);
            memcpy(ex, n, e - n);
            ex[e - n] = 0;
            // If generating dll then force dll extension
            if (global.params.dll)
                ex = FileName::forceExt(ex, global.dll_ext)->toChars();
        }
        else
            ex = (char *)"a.out";       // no extension, so give up
        argv.push(ex);
        global.params.exefile = ex;
    }

    // Make sure path to exe file exists
    {   char *p = FileName::path(global.params.exefile);
        FileName::ensurePathExists(p);
        mem.free(p);
    }

    if (global.params.symdebug)
        argv.push((char *)"-g");

    if (global.params.is64bit)
        argv.push((char *)"-m64");
    else
        argv.push((char *)"-m32");

    if (global.params.map || global.params.mapfile)
    {
        argv.push((char *)"-Xlinker");
#if __APPLE__
        argv.push((char *)"-map");
#else
        argv.push((char *)"-Map");
#endif
        if (!global.params.mapfile)
        {
            FileName *fn = FileName::forceExt(global.params.exefile, "map");

            char *path = FileName::path(global.params.exefile);
            char *p;
            if (path[0] == '\0')
                p = FileName::combine(global.params.objdir, fn->toChars());
            else
                p = fn->toChars();

            global.params.mapfile = p;
        }
        argv.push((char *)"-Xlinker");
        argv.push(global.params.mapfile);
    }

    if (0 && global.params.exefile)
    {
        /* This switch enables what is known as 'smart linking'
         * in the Windows world, where unreferenced sections
         * are removed from the executable. It eliminates unreferenced
         * functions, essentially making a 'library' out of a module.
         * Although it is documented to work with ld version 2.13,
         * in practice it does not, but just seems to be ignored.
         * Thomas Kuehne has verified that it works with ld 2.16.1.
         * BUG: disabled because it causes exception handling to fail
         * because EH sections are "unreferenced" and elided
         */
        argv.push((char *)"-Xlinker");
        argv.push((char *)"--gc-sections");
    }

    for (size_t i = 0; i < global.params.linkswitches->dim; i++)
    {   char *p = global.params.linkswitches->tdata()[i];
        if (!p || !p[0] || !(p[0] == '-' && p[1] == 'l'))
            // Don't need -Xlinker if switch starts with -l
            argv.push((char *)"-Xlinker");
        argv.push(p);
    }

    /* Add each library, prefixing it with "-l".
     * The order of libraries passed is:
     *  1. any libraries passed with -L command line switch
     *  2. libraries specified on the command line
     *  3. libraries specified by pragma(lib), which were appended
     *     to global.params.libfiles.
     *  4. standard libraries.
     */
    for (size_t i = 0; i < global.params.libfiles->dim; i++)
    {   char *p = global.params.libfiles->tdata()[i];
        size_t plen = strlen(p);
        if (plen > 2 && p[plen - 2] == '.' && p[plen -1] == 'a')
            argv.push(p);
        else
        {
            char *s = (char *)mem.malloc(plen + 3);
            s[0] = '-';
            s[1] = 'l';
            memcpy(s + 2, p, plen + 1);
            argv.push(s);
        }
    }

    /* Standard libraries must go after user specified libraries
     * passed with -l.
     */
    const char *libname = (global.params.symdebug)
                                ? global.params.debuglibname
                                : global.params.defaultlibname;
    size_t slen = strlen(libname);
    if (slen)
    {
        char *buf = (char *)malloc(2 + slen + 1);
        strcpy(buf, "-l");
        strcpy(buf + 2, libname);
        argv.push(buf);             // turns into /usr/lib/libphobos2.a
    }

//    argv.push((void *)"-ldruntime");
    argv.push((char *)"-lpthread");
    argv.push((char *)"-lm");
#if linux && DMDV2
    // Changes in ld for Ubuntu 11.10 require this to appear after phobos2
    argv.push((char *)"-lrt");
#endif

    if (!global.params.quiet || global.params.verbose)
    {
        // Print it
        for (size_t i = 0; i < argv.dim; i++)
            printf("%s ", argv.tdata()[i]);
        printf("\n");
        fflush(stdout);
    }

    argv.push(NULL);
#if HAS_POSIX_SPAWN
    int spawn_err = posix_spawnp(&childpid, argv.tdata()[0], NULL, NULL, argv.tdata(), environ);
    if (spawn_err != 0)
    {
        perror(argv.tdata()[0]);
        return -1;
    }
#else
    childpid = fork();
    if (childpid == 0)
    {
        execvp(argv.tdata()[0], argv.tdata());
        perror(argv.tdata()[0]);           // failed to execute
        return -1;
    }
    else if (childpid == -1)
    {
        perror("Unable to fork");
        return -1;
    }
#endif

    waitpid(childpid, &status, 0);

    if (WIFEXITED(status))
    {
        status = WEXITSTATUS(status);
        if (status)
            printf("--- errorlevel %d\n", status);
    }
    else if (WIFSIGNALED(status))
    {
        printf("--- killed by signal %d\n", WTERMSIG(status));
        status = 1;
    }
    return status;
#else
    printf ("Linking is not yet supported for this version of DMD.\n");
    return -1;
#endif
}
Exemple #5
0
void LibOMF::scanObjModule(ObjModule *om)
{   int easyomf;
    unsigned u;
    unsigned char result = 0;
    char name[LIBIDMAX + 1];

    Strings names;
    names.push(NULL);           // don't use index 0

    assert(om);
    easyomf = 0;                                // assume not EASY-OMF
    unsigned char *pend = om->base + om->length;

    unsigned char *pnext;
    for (unsigned char *p = om->base; 1; p = pnext)
    {
        assert(p < pend);
        unsigned char recTyp = *p++;
        unsigned short recLen = *(unsigned short *)p;
        p += 2;
        pnext = p + recLen;
        recLen--;                               // forget the checksum

        switch (recTyp)
        {
            case LNAMES:
            case LLNAMES:
                while (p + 1 < pnext)
                {
                    parseName(&p, name);
                    names.push(strdup(name));
                }
                break;

            case PUBDEF:
                if (easyomf)
                    recTyp = PUB386;            // convert to MS format
            case PUB386:
                if (!(parseIdx(&p) | parseIdx(&p)))
                    p += 2;                     // skip seg, grp, frame
                while (p + 1 < pnext)
                {
                    parseName(&p, name);
                    p += (recTyp == PUBDEF) ? 2 : 4;    // skip offset
                    parseIdx(&p);                               // skip type index
                    addSymbol(om, name);
                }
                break;

            case COMDAT:
                if (easyomf)
                    recTyp = COMDAT+1;          // convert to MS format
            case COMDAT+1:
            {
                int pickAny = 0;

                if (*p++ & 5)           // if continuation or local comdat
                    break;

                unsigned char attr = *p++;
                if (attr & 0xF0)        // attr: if multiple instances allowed
                    pickAny = 1;
                p++;                    // align

                p += 2;                 // enum data offset
                if (recTyp == COMDAT+1)
                    p += 2;                     // enum data offset

                parseIdx(&p);                   // type index

                if ((attr & 0x0F) == 0) // if explicit allocation
                {   parseIdx(&p);               // base group
                    parseIdx(&p);               // base segment
                }

                unsigned idx = parseIdx(&p);    // public name index
                if( idx == 0 || idx >= names.dim)
                {
                    //debug(printf("[s] name idx=%d, uCntNames=%d\n", idx, uCntNames));
                    error("corrupt COMDAT");
                    return;
                }

                //printf("[s] name='%s'\n",name);
                addSymbol(om, names[idx],pickAny);
                break;
            }
            case ALIAS:
                while (p + 1 < pnext)
                {
                    parseName(&p, name);
                    addSymbol(om, name);
                    parseName(&p, name);
                }
                break;

            case MODEND:
            case M386END:
                result = 1;
                goto Ret;

            case COMENT:
                // Recognize Phar Lap EASY-OMF format
                {   static unsigned char omfstr[7] =
                        {0x80,0xAA,'8','0','3','8','6'};

                    if (recLen == sizeof(omfstr))
                    {
                        for (unsigned i = 0; i < sizeof(omfstr); i++)
                            if (*p++ != omfstr[i])
                                goto L1;
                        easyomf = 1;
                        break;
                    L1: ;
                    }
                }
                // Recognize .IMPDEF Import Definition Records
                {   static unsigned char omfstr[] =
                        {0,0xA0,1};

                    if (recLen >= 7)
                    {
                        p++;
                        for (unsigned i = 1; i < sizeof(omfstr); i++)
                            if (*p++ != omfstr[i])
                                goto L2;
                        p++;            // skip OrdFlag field
                        parseName(&p, name);
                        addSymbol(om, name);
                        break;
                    L2: ;
                    }
                }
                break;

            default:
                // ignore
                ;
        }
    }
Ret:
    for (u = 1; u < names.dim; u++)
        free(names[u]);
}
Exemple #6
0
int main(int argc, char** argv)
{
    mem.init();                         // initialize storage allocator
    mem.setStackBottom(&argv);
#if _WIN32 && __DMC__
    mem.addroots((char *)&_xi_a, (char *)&_end);
#endif

    // stack trace on signals
    llvm::sys::PrintStackTraceOnErrorSignal();

    Strings files;
    const char *p, *ext;
    Module *m;
    int status = EXIT_SUCCESS;

    global.init();
    global.version = ldc::dmd_version;
    global.ldc_version = ldc::ldc_version;
    global.llvm_version = ldc::llvm_version;

    // Set some default values
#if _WIN32
    char buf[MAX_PATH];
    GetModuleFileName(NULL, buf, MAX_PATH);
    global.params.argv0 = buf;
#else
    global.params.argv0 = argv[0];
#endif
    global.params.useSwitchError = 1;
    global.params.useArrayBounds = 2;

    global.params.linkswitches = new Strings();
    global.params.libfiles = new Strings();
    global.params.objfiles = new Strings();
    global.params.ddocfiles = new Strings();

    global.params.moduleDeps = NULL;
    global.params.moduleDepsFile = NULL;

    // Set predefined version identifiers
    VersionCondition::addPredefinedGlobalIdent("LLVM"); // For backwards compatibility.
    VersionCondition::addPredefinedGlobalIdent("LDC");
    VersionCondition::addPredefinedGlobalIdent("all");
    VersionCondition::addPredefinedGlobalIdent("D_Version2");

    // build complete fixed up list of command line arguments
    std::vector<const char*> final_args;
    final_args.reserve(argc);

    // insert command line args until -run is reached
    int run_argnum = 1;
    while (run_argnum < argc && strncmp(argv[run_argnum], "-run", 4) != 0)
        ++run_argnum;
    final_args.insert(final_args.end(), &argv[0], &argv[run_argnum]);

    // read the configuration file
    ConfigFile cfg_file;

    // just ignore errors for now, they are still printed
    cfg_file.read(global.params.argv0, (void*)main, "ldc2.conf");

    // insert config file additions to the argument list
    final_args.insert(final_args.end(), cfg_file.switches_begin(), cfg_file.switches_end());

    // insert -run and everything beyond
    final_args.insert(final_args.end(), &argv[run_argnum], &argv[argc]);

#if 0
    for (size_t i = 0; i < final_args.size(); ++i)
    {
        printf("final_args[%zu] = %s\n", i, final_args[i]);
    }
#endif

    // Initialize LLVM.
    // Initialize targets first, so that --version shows registered targets.
    llvm::InitializeAllTargetInfos();
    llvm::InitializeAllTargets();
    llvm::InitializeAllTargetMCs();
    llvm::InitializeAllAsmPrinters();
    llvm::InitializeAllAsmParsers();

    // Handle fixed-up arguments!
    cl::SetVersionPrinter(&printVersion);
    cl::ParseCommandLineOptions(final_args.size(), const_cast<char**>(&final_args[0]),
        "LDC - the LLVM D compiler\n"
#if LDC_LLVM_VER < 302
        , true
#endif
    );

    // Print config file path if -v was passed
    if (global.params.verbose) {
        const std::string& path = cfg_file.path();
        if (!path.empty())
            printf("config    %s\n", path.c_str());
    }

    bool skipModules = mCPU == "help" ||(!mAttrs.empty() && mAttrs.front() == "help");

    // Negated options
    global.params.link = !compileOnly;
    global.params.obj = !dontWriteObj;
    global.params.useInlineAsm = !noAsm;

    // String options: std::string --> char*
    initFromString(global.params.objname, objectFile);
    initFromString(global.params.objdir, objectDir);

    initFromString(global.params.docdir, ddocDir);
    initFromString(global.params.docname, ddocFile);
    global.params.doDocComments |=
        global.params.docdir || global.params.docname;

    initFromString(global.params.xfilename, jsonFile);
    if (global.params.xfilename)
        global.params.doXGeneration = true;

    initFromString(global.params.hdrdir, hdrDir);
    initFromString(global.params.hdrname, hdrFile);
    global.params.doHdrGeneration |=
        global.params.hdrdir || global.params.hdrname;

    initFromString(global.params.moduleDepsFile, moduleDepsFile);
    if (global.params.moduleDepsFile != NULL)
    {
         global.params.moduleDeps = new OutBuffer;
    }

    processVersions(debugArgs, "debug",
        DebugCondition::setGlobalLevel,
        DebugCondition::addGlobalIdent);
    processVersions(versions, "version",
        VersionCondition::setGlobalLevel,
        VersionCondition::addGlobalIdent);

    global.params.output_o =
        (opts::output_o == cl::BOU_UNSET
            && !(opts::output_bc || opts::output_ll || opts::output_s))
        ? OUTPUTFLAGdefault
        : opts::output_o == cl::BOU_TRUE
            ? OUTPUTFLAGset
            : OUTPUTFLAGno;
    global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno;
    global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno;
    global.params.output_s  = opts::output_s  ? OUTPUTFLAGset : OUTPUTFLAGno;

    templateLinkage =
        opts::linkonceTemplates ? LLGlobalValue::LinkOnceODRLinkage
                                : LLGlobalValue::WeakODRLinkage;

    if (global.params.run || !runargs.empty()) {
        // FIXME: how to properly detect the presence of a PositionalEatsArgs
        // option without parameters? We want to emit an error in that case...
        // You'd think getNumOccurrences would do it, but it just returns the
        // number of parameters)
        // NOTE: Hacked around it by detecting -run in getenv_setargv(), where
        // we're looking for it anyway, and pre-setting the flag...
        global.params.run = true;
        if (!runargs.empty()) {
            char const * name = runargs[0].c_str();
            char const * ext = FileName::ext(name);
            if (ext && FileName::equals(ext, "d") == 0 &&
                FileName::equals(ext, "di") == 0) {
                error("-run must be followed by a source file, not '%s'", name);
            }

            files.push(mem.strdup(name));
            runargs.erase(runargs.begin());
        } else {
            global.params.run = false;
            error("Expected at least one argument to '-run'\n");
        }
    }


    files.reserve(fileList.size());
    typedef std::vector<std::string>::iterator It;
    for(It I = fileList.begin(), E = fileList.end(); I != E; ++I)
        if (!I->empty())
            files.push(mem.strdup(I->c_str()));

    if (global.errors)
    {
        fatal();
    }
    if (files.dim == 0 && !skipModules)
    {
        cl::PrintHelpMessage();
        return EXIT_FAILURE;
    }

    Array* libs;
    if (global.params.symdebug)
    {
        libs = global.params.debuglibnames;
    }
    else
        libs = global.params.defaultlibnames;

    if (!noDefaultLib)
    {
        if (libs)
        {
            for (unsigned i = 0; i < libs->dim; i++)
            {
                char* lib = static_cast<char *>(libs->data[i]);
                char *arg = static_cast<char *>(mem.malloc(strlen(lib) + 3));
                strcpy(arg, "-l");
                strcpy(arg+2, lib);
                global.params.linkswitches->push(arg);
            }
        }
        else
        {
            global.params.linkswitches->push(mem.strdup("-ldruntime-ldc"));
        }
    }

    if (global.params.useUnitTests)
        global.params.useAssert = 1;

    // Bounds checking is a bit peculiar: -enable/disable-boundscheck is an
    // absolute decision. Only if no explicit option is specified, -release
    // downgrades useArrayBounds 2 to 1 (only for safe functions).
    if (opts::boundsChecks == cl::BOU_UNSET)
        global.params.useArrayBounds = opts::nonSafeBoundsChecks ? 2 : 1;
    else
        global.params.useArrayBounds = (opts::boundsChecks == cl::BOU_TRUE) ? 2 : 0;

    // LDC output determination

    // if we don't link, autodetect target from extension
    if(!global.params.link && !createStaticLib && global.params.objname) {
        ext = FileName::ext(global.params.objname);
        bool autofound = false;
        if (!ext) {
            // keep things as they are
        } else if (strcmp(ext, global.ll_ext) == 0) {
            global.params.output_ll = OUTPUTFLAGset;
            autofound = true;
        } else if (strcmp(ext, global.bc_ext) == 0) {
            global.params.output_bc = OUTPUTFLAGset;
            autofound = true;
        } else if (strcmp(ext, global.s_ext) == 0) {
            global.params.output_s = OUTPUTFLAGset;
            autofound = true;
        } else if (strcmp(ext, global.obj_ext) == 0 || strcmp(ext, global.obj_ext_alt) == 0) {
            global.params.output_o = OUTPUTFLAGset;
            autofound = true;
        } else {
            // append dot, so forceExt won't change existing name even if it contains dots
            size_t len = strlen(global.params.objname);
            char* s = static_cast<char *>(mem.malloc(len + 1 + 1));
            memcpy(s, global.params.objname, len);
            s[len] = '.';
            s[len+1] = 0;
            global.params.objname = s;

        }
        if(autofound && global.params.output_o == OUTPUTFLAGdefault)
            global.params.output_o = OUTPUTFLAGno;
    }

    // only link if possible
    if (!global.params.obj || !global.params.output_o || createStaticLib)
        global.params.link = 0;

    if (createStaticLib && createSharedLib)
        error("-lib and -shared switches cannot be used together");

    if (createSharedLib && mRelocModel == llvm::Reloc::Default)
        mRelocModel = llvm::Reloc::PIC_;

    if (global.params.link && !createSharedLib)
    {
        global.params.exefile = global.params.objname;
        if (files.dim > 1)
            global.params.objname = NULL;
    }
    else if (global.params.run)
    {
        error("flags conflict with -run");
        fatal();
    }
    else if (global.params.objname && files.dim > 1) {
        if (createStaticLib || createSharedLib)
        {
            singleObj = true;
        }
        if (!singleObj)
        {
            error("multiple source files, but only one .obj name");
            fatal();
        }
    }

    if (soname.getNumOccurrences() > 0 && !createSharedLib) {
        error("-soname can be used only when building a shared library");
        fatal();
    }

    // create a proper target
    Ir ir;

    // Set up the TargetMachine.
    ExplicitBitness::Type bitness = ExplicitBitness::None;
    if ((m32bits || m64bits) && (!mArch.empty() || !mTargetTriple.empty()))
        error("-m32 and -m64 switches cannot be used together with -march and -mtriple switches");

    if (m32bits)
        bitness = ExplicitBitness::M32;
    if (m64bits)
    {
        if (bitness != ExplicitBitness::None)
        {
            error("cannot use both -m32 and -m64 options");
        }
    }

    if (global.errors)
        fatal();

    gTargetMachine = createTargetMachine(mTargetTriple, mArch, mCPU, mAttrs, bitness,
        mRelocModel, mCodeModel, codeGenOptLevel(), global.params.symdebug);
    llvm::Triple targetTriple = llvm::Triple(gTargetMachine->getTargetTriple());
    global.params.targetTriple = targetTriple;
    global.params.trace        = false;
    global.params.isLinux      = targetTriple.getOS() == llvm::Triple::Linux;
    global.params.isOSX        = targetTriple.isMacOSX();
    global.params.isWindows    = targetTriple.isOSWindows();
    global.params.isFreeBSD    = targetTriple.getOS() == llvm::Triple::FreeBSD;
    global.params.isOpenBSD    = targetTriple.getOS() == llvm::Triple::OpenBSD;
    global.params.isSolaris    = targetTriple.getOS() == llvm::Triple::Solaris;

#if LDC_LLVM_VER >= 302
    gDataLayout = gTargetMachine->getDataLayout();
#else
    gDataLayout = gTargetMachine->getTargetData();
#endif

    // Starting with LLVM 3.1 we could also use global.params.targetTriple.isArch64Bit();
    global.params.is64bit = gDataLayout->getPointerSizeInBits(ADDRESS_SPACE) == 64;

    switch (global.params.targetTriple.getArch())
    {
        case llvm::Triple::x86:
            VersionCondition::addPredefinedGlobalIdent("X86");
            if (global.params.useInlineAsm) {
                VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86");
            }
            VersionCondition::addPredefinedGlobalIdent("D_HardFloat");
            break;
        case llvm::Triple::x86_64:
            VersionCondition::addPredefinedGlobalIdent("X86_64");
            if (global.params.useInlineAsm) {
                VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64");
            }
            VersionCondition::addPredefinedGlobalIdent("D_HardFloat");
            break;
        case llvm::Triple::ppc:
            // FIXME: Detect soft float (PPC_SoftFP/PPC_HardFP).
            VersionCondition::addPredefinedGlobalIdent("PPC");
            break;
        case llvm::Triple::ppc64:
            VersionCondition::addPredefinedGlobalIdent("PPC64");
            VersionCondition::addPredefinedGlobalIdent("D_HardFloat");
            break;
        case llvm::Triple::arm:
            // FIXME: Detect various FP ABIs (ARM_Soft, ARM_SoftFP, ARM_HardFP).
            VersionCondition::addPredefinedGlobalIdent("ARM");
            break;
        case llvm::Triple::thumb:
            VersionCondition::addPredefinedGlobalIdent("ARM");
            VersionCondition::addPredefinedGlobalIdent("Thumb"); // For backwards compatibility.
            VersionCondition::addPredefinedGlobalIdent("ARM_Thumb");
            VersionCondition::addPredefinedGlobalIdent("ARM_Soft");
            VersionCondition::addPredefinedGlobalIdent("D_SoftFloat");
            break;
        case llvm::Triple::mips:
        case llvm::Triple::mipsel:
            // FIXME: Detect O32/N32 variants (MIPS_{O32,N32}[_SoftFP,_HardFP]).
            VersionCondition::addPredefinedGlobalIdent("MIPS");
            break;
        case llvm::Triple::mips64:
        case llvm::Triple::mips64el:
            // FIXME: Detect N64 variants (MIPS64_N64[_SoftFP,_HardFP]).
            VersionCondition::addPredefinedGlobalIdent("MIPS64");
            break;
        case llvm::Triple::sparc:
            // FIXME: Detect SPARC v8+ (SPARC_V8Plus).
            // FIXME: Detect soft float (SPARC_SoftFP/SPARC_HardFP).
            VersionCondition::addPredefinedGlobalIdent("SPARC");
            break;
        case llvm::Triple::sparcv9:
            VersionCondition::addPredefinedGlobalIdent("SPARC64");
            VersionCondition::addPredefinedGlobalIdent("D_HardFloat");
            break;
        default:
            error("invalid cpu architecture specified: %s", global.params.targetTriple.getArchName().str().c_str());
            fatal();
    }

    // endianness
    if (gDataLayout->isLittleEndian()) {
        VersionCondition::addPredefinedGlobalIdent("LittleEndian");
    }
    else {
        VersionCondition::addPredefinedGlobalIdent("BigEndian");
    }

    // a generic 64bit version
    if (global.params.is64bit) {
        VersionCondition::addPredefinedGlobalIdent("LLVM64"); // For backwards compatibility.
        VersionCondition::addPredefinedGlobalIdent("D_LP64");
    }

    if (gTargetMachine->getRelocationModel() == llvm::Reloc::PIC_) {
        VersionCondition::addPredefinedGlobalIdent("D_PIC");
    }

    // parse the OS out of the target triple
    // see http://gcc.gnu.org/install/specific.html for details
    // also llvm's different SubTargets have useful information
    switch (global.params.targetTriple.getOS())
    {
        case llvm::Triple::Win32:
            VersionCondition::addPredefinedGlobalIdent("Windows");
            VersionCondition::addPredefinedGlobalIdent(global.params.is64bit ? "Win64" : "Win32");
            break;
        case llvm::Triple::MinGW32:
            VersionCondition::addPredefinedGlobalIdent("Windows");
            VersionCondition::addPredefinedGlobalIdent(global.params.is64bit ? "Win64" : "Win32");
            VersionCondition::addPredefinedGlobalIdent("mingw32"); // For backwards compatibility.
            VersionCondition::addPredefinedGlobalIdent("MinGW");
            break;
        case llvm::Triple::Cygwin:
            error("Cygwin is not yet supported");
            fatal();
            VersionCondition::addPredefinedGlobalIdent("Cygwin");
            break;
        case llvm::Triple::Linux:
            VersionCondition::addPredefinedGlobalIdent("linux");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::Haiku:
            VersionCondition::addPredefinedGlobalIdent("Haiku");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::Darwin:
            VersionCondition::addPredefinedGlobalIdent("OSX");
            VersionCondition::addPredefinedGlobalIdent("darwin"); // For backwards compatibility.
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::FreeBSD:
            VersionCondition::addPredefinedGlobalIdent("freebsd"); // For backwards compatibility.
            VersionCondition::addPredefinedGlobalIdent("FreeBSD");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::Solaris:
            VersionCondition::addPredefinedGlobalIdent("solaris"); // For backwards compatibility.
            VersionCondition::addPredefinedGlobalIdent("Solaris");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::DragonFly:
            VersionCondition::addPredefinedGlobalIdent("DragonFlyBSD");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::NetBSD:
            VersionCondition::addPredefinedGlobalIdent("NetBSD");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::OpenBSD:
            VersionCondition::addPredefinedGlobalIdent("OpenBSD");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
#if LDC_LLVM_VER >= 302
        case llvm::Triple::AIX:
            VersionCondition::addPredefinedGlobalIdent("AIX");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
#endif
        default:
            error("target '%s' is not yet supported", global.params.targetTriple.str().c_str());
            fatal();
    }

    // Expose LLVM version to runtime
#define STR(x) #x
#define XSTR(x) STR(x)
    VersionCondition::addPredefinedGlobalIdent("LDC_LLVM_" XSTR(LDC_LLVM_VER));
#undef XSTR
#undef STR

    if (global.params.targetTriple.isOSWindows()) {
        global.dll_ext = "dll";
        global.lib_ext = "lib";
    } else {
        global.dll_ext = "so";
        global.lib_ext = "a";
    }

    // added in 1.039
    if (global.params.doDocComments)
        VersionCondition::addPredefinedGlobalIdent("D_Ddoc");

    // unittests?
    if (global.params.useUnitTests)
        VersionCondition::addPredefinedGlobalIdent("unittest");

    if (global.params.useAssert)
        VersionCondition::addPredefinedGlobalIdent("assert");

    if (!global.params.useArrayBounds)
        VersionCondition::addPredefinedGlobalIdent("D_NoBoundsChecks");

    // Initialization
    Type::init(&ir);
    Id::initialize();
    Module::init();
    Target::init();
    Expression::init();
    initPrecedence();

    backend_init();

    //printf("%d source files\n",files.dim);

    // Build import search path
    if (global.params.imppath)
    {
        for (unsigned i = 0; i < global.params.imppath->dim; i++)
        {
            char *path = static_cast<char *>(global.params.imppath->data[i]);
            Strings *a = FileName::splitPath(path);

            if (a)
            {
                if (!global.path)
                    global.path = new Strings();
                global.path->append(a);
            }
        }
    }

    // Build string import search path
    if (global.params.fileImppath)
    {
        for (unsigned i = 0; i < global.params.fileImppath->dim; i++)
        {
            char *path = static_cast<char *>(global.params.fileImppath->data[i]);
            Strings *a = FileName::splitPath(path);

            if (a)
            {
                if (!global.filePath)
                    global.filePath = new Strings();
                global.filePath->append(a);
            }
        }
    }

    if (global.params.addMain)
    {
        // a dummy name, we never actually look up this file
        files.push(const_cast<char*>(global.main_d));
    }

    // Create Modules
    Modules modules;
    modules.reserve(files.dim);
    for (unsigned i = 0; i < files.dim; i++)
    {   Identifier *id;
        const char *ext;
        const char *name;

        p = static_cast<char *>(files.data[i]);

        p = FileName::name(p);      // strip path
        ext = FileName::ext(p);
        if (ext)
        {
#if POSIX
            if (strcmp(ext, global.obj_ext) == 0 ||
                strcmp(ext, global.bc_ext) == 0)
#else
            if (Port::stricmp(ext, global.obj_ext) == 0 ||
                Port::stricmp(ext, global.obj_ext_alt) == 0 ||
                Port::stricmp(ext, global.bc_ext) == 0)
#endif
            {
                global.params.objfiles->push(static_cast<char *>(files.data[i]));
                continue;
            }

#if POSIX
            if (strcmp(ext, "a") == 0)
#elif __MINGW32__
            if (Port::stricmp(ext, "a") == 0)
#else
            if (Port::stricmp(ext, "lib") == 0)
#endif
            {
                global.params.libfiles->push(static_cast<char *>(files.data[i]));
                continue;
            }

            if (strcmp(ext, global.ddoc_ext) == 0)
            {
                global.params.ddocfiles->push(static_cast<char *>(files.data[i]));
                continue;
            }

            if (FileName::equals(ext, global.json_ext))
            {
                global.params.doXGeneration = 1;
                global.params.xfilename = static_cast<char *>(files.data[i]);
                continue;
            }

#if !POSIX
            if (Port::stricmp(ext, "res") == 0)
            {
                global.params.resfile = static_cast<char *>(files.data[i]);
                continue;
            }

            if (Port::stricmp(ext, "def") == 0)
            {
                global.params.deffile = static_cast<char *>(files.data[i]);
                continue;
            }

            if (Port::stricmp(ext, "exe") == 0)
            {
                global.params.exefile = static_cast<char *>(files.data[i]);
                continue;
            }
#endif

            if (Port::stricmp(ext, global.mars_ext) == 0 ||
                Port::stricmp(ext, global.hdr_ext) == 0 ||
                FileName::equals(ext, "dd"))
            {
                ext--;          // skip onto '.'
                assert(*ext == '.');
                char *tmp = static_cast<char *>(mem.malloc((ext - p) + 1));
                memcpy(tmp, p, ext - p);
                tmp[ext - p] = 0;      // strip extension
                name = tmp;

                if (name[0] == 0 ||
                    strcmp(name, "..") == 0 ||
                    strcmp(name, ".") == 0)
                {
                    goto Linvalid;
                }
            }
            else
            {   error("unrecognized file extension %s\n", ext);
                fatal();
            }
        }
        else
        {   name = p;
            if (!*p)
            {
        Linvalid:
                error("invalid file name '%s'", static_cast<char *>(files.data[i]));
                fatal();
            }
            name = p;
        }

        id = Lexer::idPool(name);
        m = new Module(static_cast<char *>(files.data[i]), id, global.params.doDocComments, global.params.doHdrGeneration);
        m->isRoot = true;
        modules.push(m);
    }

    // Read files, parse them
    for (unsigned i = 0; i < modules.dim; i++)
    {
        m = static_cast<Module *>(modules.data[i]);
        if (global.params.verbose)
            printf("parse     %s\n", m->toChars());
        if (!Module::rootModule)
            Module::rootModule = m;
        m->importedFrom = m;

        if (strcmp(m->srcfile->name->str, global.main_d) == 0)
        {
            static const char buf[] = "void main(){}";
            m->srcfile->setbuffer((void *)buf, sizeof(buf));
            m->srcfile->ref = 1;
        }
        else
        {
            m->read(Loc());
        }

        m->parse(global.params.doDocComments);
        m->buildTargetFiles(singleObj);
        m->deleteObjFile();
        if (m->isDocFile)
        {
            m->gendocfile();

            // Remove m from list of modules
            modules.remove(i);
            i--;
        }
    }
    if (global.errors)
        fatal();

    if (global.params.doHdrGeneration)
    {
        /* Generate 'header' import files.
         * Since 'header' import files must be independent of command
         * line switches and what else is imported, they are generated
         * before any semantic analysis.
         */
        for (unsigned i = 0; i < modules.dim; i++)
        {
            m = static_cast<Module *>(modules.data[i]);
            if (global.params.verbose)
                printf("import    %s\n", m->toChars());
            m->genhdrfile();
        }
    }
    if (global.errors)
        fatal();

    // load all unconditional imports for better symbol resolving
    for (unsigned i = 0; i < modules.dim; i++)
    {
       m = static_cast<Module *>(modules.data[i]);
       if (global.params.verbose)
           printf("importall %s\n", m->toChars());
       m->importAll(0);
    }
    if (global.errors)
       fatal();

    // Do semantic analysis
    for (unsigned i = 0; i < modules.dim; i++)
    {
        m = static_cast<Module *>(modules.data[i]);
        if (global.params.verbose)
            printf("semantic  %s\n", m->toChars());
        m->semantic();
    }
    if (global.errors)
        fatal();

    Module::dprogress = 1;
    Module::runDeferredSemantic();

    // Do pass 2 semantic analysis
    for (unsigned i = 0; i < modules.dim; i++)
    {
        m = static_cast<Module *>(modules.data[i]);
        if (global.params.verbose)
            printf("semantic2 %s\n", m->toChars());
        m->semantic2();
    }
    if (global.errors)
        fatal();

    // Do pass 3 semantic analysis
    for (unsigned i = 0; i < modules.dim; i++)
    {
        m = static_cast<Module *>(modules.data[i]);
        if (global.params.verbose)
            printf("semantic3 %s\n", m->toChars());
        m->semantic3();
    }
    if (global.errors)
        fatal();

    // This doesn't play nice with debug info at the moment.
    //
    // Also, don't run the additional semantic3 passes when building unit tests.
    // This is basically a huge hack around the fact that linking against a
    // library is supposed to require the same compiler flags as when it was
    // built, but -unittest is usually not thought to behave like this from a
    // user perspective.
    //
    // Thus, if a library contained some functions in version(unittest), for
    // example the tests in std.concurrency, and we ended up inline-scannin
    // these functions while doing an -unittest build of a client application,
    // we could end up referencing functions that we think are
    // availableExternally, but have never been touched when the library was built.
    //
    // Alternatively, we could also amend the availableExternally detection
    // logic (e.g. just codegen everything on -unittest builds), but the extra
    // inlining is unlikely to be important for test builds anyway.
    if (!global.params.symdebug && willInline() && !global.params.useUnitTests)
    {
        global.inExtraInliningSemantic = true;
        Logger::println("Running some extra semantic3's for inlining purposes");
        {
            // Do pass 3 semantic analysis on all imported modules,
            // since otherwise functions in them cannot be inlined
            for (unsigned i = 0; i < Module::amodules.dim; i++)
            {
                m = static_cast<Module *>(Module::amodules.data[i]);
                if (global.params.verbose)
                    printf("semantic3 %s\n", m->toChars());
                m->semantic2();
                m->semantic3();
            }
            if (global.errors)
                fatal();
        }
        global.inExtraInliningSemantic = false;
    }
    if (global.errors || global.warnings)
        fatal();

    // write module dependencies to file if requested
    if (global.params.moduleDepsFile != NULL)
    {
        assert (global.params.moduleDepsFile != NULL);

        File deps(global.params.moduleDepsFile);
        OutBuffer* ob = global.params.moduleDeps;
        deps.setbuffer(static_cast<void*>(ob->data), ob->offset);
        deps.write();
    }

    // collects llvm modules to be linked if singleobj is passed
    std::vector<llvm::Module*> llvmModules;
    llvm::LLVMContext& context = llvm::getGlobalContext();

    // Generate output files
    for (unsigned i = 0; i < modules.dim; i++)
    {
        m = static_cast<Module *>(modules.data[i]);
        if (global.params.verbose)
            printf("code      %s\n", m->toChars());
        if (global.params.obj)
        {
            llvm::Module* lm = m->genLLVMModule(context, &ir);
            if (!singleObj)
            {
                m->deleteObjFile();
                writeModule(lm, m->objfile->name->str);
                global.params.objfiles->push(const_cast<char*>(m->objfile->name->str));
                delete lm;
            }
            else
                llvmModules.push_back(lm);
        }
        if (global.errors)
            m->deleteObjFile();
        else
        {
            if (global.params.doDocComments)
            m->gendocfile();
        }
    }

    // internal linking for singleobj
    if (singleObj && llvmModules.size() > 0)
    {
        Module* m = static_cast<Module*>(modules.data[0]);

        char* oname;
        const char* filename;
        if ((oname = global.params.exefile) || (oname = global.params.objname))
        {
            filename = FileName::forceExt(oname, global.obj_ext);
            if (global.params.objdir)
            {
                filename = FileName::combine(global.params.objdir, FileName::name(filename));
            }
        }
        else
            filename = m->objfile->name->str;

#if 1
        // Temporary workaround for http://llvm.org/bugs/show_bug.cgi?id=11479.
        char* moduleName = const_cast<char*>(filename);
#else
        char* moduleName = m->toChars();
#endif

#if LDC_LLVM_VER >= 303
        llvm::Module *dest = new llvm::Module(moduleName, context);
        llvm::Linker linker(dest);
#else
        llvm::Linker linker("ldc", moduleName, context);
#endif

        std::string errormsg;
        for (size_t i = 0; i < llvmModules.size(); i++)
        {
#if LDC_LLVM_VER >= 303
            if (linker.linkInModule(llvmModules[i], llvm::Linker::DestroySource, &errormsg))
#else
            if (linker.LinkInModule(llvmModules[i], &errormsg))
#endif
                error("%s", errormsg.c_str());
            delete llvmModules[i];
        }

        m->deleteObjFile();
        writeModule(linker.getModule(), filename);
        global.params.objfiles->push(const_cast<char*>(filename));

#if LDC_LLVM_VER >= 303
        delete dest;
#endif
    }

    // output json file
    if (global.params.doXGeneration)
    {
        OutBuffer buf;
        json_generate(&buf, &modules);

        // Write buf to file
        const char *name = global.params.xfilename;

        if (name && name[0] == '-' && name[1] == 0)
        {   // Write to stdout; assume it succeeds
            int n = fwrite(buf.data, 1, buf.offset, stdout);
            assert(n == buf.offset);        // keep gcc happy about return values
        }
        else
        {
            /* The filename generation code here should be harmonized with Module::setOutfile()
             */

            const char *jsonfilename;

            if (name && *name)
            {
                jsonfilename = FileName::defaultExt(name, global.json_ext);
            }
            else
            {
                // Generate json file name from first obj name
                const char *n = (*global.params.objfiles)[0];
                n = FileName::name(n);

                //if (!FileName::absolute(name))
                    //name = FileName::combine(dir, name);

                jsonfilename = FileName::forceExt(n, global.json_ext);
            }

            FileName::ensurePathToNameExists(jsonfilename);

            File *jsonfile = new File(jsonfilename);

            jsonfile->setbuffer(buf.data, buf.offset);
            jsonfile->ref = 1;
            jsonfile->writev();
        }
    }

    backend_term();
    if (global.errors)
        fatal();

    if (!global.params.objfiles->dim)
    {
        if (global.params.link)
            error("no object files to link");
        else if (createStaticLib)
            error("no object files");
    }
    else
    {
        if (global.params.link)
            status = linkObjToBinary(createSharedLib);
        else if (createStaticLib)
            createStaticLibrary();

        if (global.params.run)
        {
            if (!status)
            {
                status = runExecutable();

                /* Delete .obj files and .exe file
                 */
                for (unsigned i = 0; i < modules.dim; i++)
                {
                    m = static_cast<Module *>(modules.data[i]);
                    m->deleteObjFile();
                }
                deleteExecutable();
            }
        }
    }

    return status;
}
Exemple #7
0
int main(int argc, char **argv)
{
    // stack trace on signals
    llvm::sys::PrintStackTraceOnErrorSignal();

    global.init();
    global.version = ldc::dmd_version;
    global.ldc_version = ldc::ldc_version;
    global.llvm_version = ldc::llvm_version;

    // Initialize LLVM before parsing the command line so that --version shows
    // registered targets.
    llvm::InitializeAllTargetInfos();
    llvm::InitializeAllTargets();
    llvm::InitializeAllTargetMCs();
    llvm::InitializeAllAsmPrinters();
    llvm::InitializeAllAsmParsers();

    initializePasses();

    bool helpOnly;
    Strings files;
    parseCommandLine(argc, argv, files, helpOnly);

    if (files.dim == 0 && !helpOnly)
    {
        cl::PrintHelpMessage();
        return EXIT_FAILURE;
    }

    if (global.errors)
        fatal();

    // Set up the TargetMachine.
    ExplicitBitness::Type bitness = ExplicitBitness::None;
    if ((m32bits || m64bits) && (!mArch.empty() || !mTargetTriple.empty()))
        error(Loc(), "-m32 and -m64 switches cannot be used together with -march and -mtriple switches");

    if (m32bits)
        bitness = ExplicitBitness::M32;
    if (m64bits)
    {
        if (bitness != ExplicitBitness::None)
            error(Loc(), "cannot use both -m32 and -m64 options");
        bitness = ExplicitBitness::M64;
    }

    if (global.errors)
        fatal();

    gTargetMachine = createTargetMachine(mTargetTriple, mArch, mCPU, mAttrs,
        bitness, mFloatABI, mRelocModel, mCodeModel, codeGenOptLevel(),
        global.params.symdebug || disableFpElim, disableLinkerStripDead);

#if LDC_LLVM_VER >= 307
    gDataLayout = gTargetMachine->getDataLayout();
#elif LDC_LLVM_VER >= 306
    gDataLayout = gTargetMachine->getSubtargetImpl()->getDataLayout();
#elif LDC_LLVM_VER >= 302
    gDataLayout = gTargetMachine->getDataLayout();
#else
    gDataLayout = gTargetMachine->getTargetData();
#endif

    {
        llvm::Triple triple = llvm::Triple(gTargetMachine->getTargetTriple());
        global.params.targetTriple = triple;
        global.params.isLinux      = triple.getOS() == llvm::Triple::Linux;
        global.params.isOSX        = triple.isMacOSX();
        global.params.isWindows    = triple.isOSWindows();
        global.params.isFreeBSD    = triple.getOS() == llvm::Triple::FreeBSD;
        global.params.isOpenBSD    = triple.getOS() == llvm::Triple::OpenBSD;
        global.params.isSolaris    = triple.getOS() == llvm::Triple::Solaris;
        global.params.isLP64       = gDataLayout->getPointerSizeInBits() == 64;
        global.params.is64bit      = triple.isArch64Bit();
    }

    // allocate the target abi
    gABI = TargetABI::getTarget();

    // Set predefined version identifiers.
    registerPredefinedVersions();
    dumpPredefinedVersions();

    if (global.params.targetTriple.isOSWindows()) {
        global.dll_ext = "dll";
        global.lib_ext = "lib";
    } else {
        global.dll_ext = "so";
        global.lib_ext = "a";
    }

    // Initialization
    Lexer::initLexer();
    Type::init();
    Id::initialize();
    Module::init();
    Target::init();
    Expression::init();
    initPrecedence();
    builtin_init();
    initTraitsStringTable();

    // Build import search path
    if (global.params.imppath)
    {
        for (unsigned i = 0; i < global.params.imppath->dim; i++)
        {
            const char *path = static_cast<const char *>(global.params.imppath->data[i]);
            Strings *a = FileName::splitPath(path);

            if (a)
            {
                if (!global.path)
                    global.path = new Strings();
                global.path->append(a);
            }
        }
    }

    // Build string import search path
    if (global.params.fileImppath)
    {
        for (unsigned i = 0; i < global.params.fileImppath->dim; i++)
        {
            const char *path = static_cast<const char *>(global.params.fileImppath->data[i]);
            Strings *a = FileName::splitPath(path);

            if (a)
            {
                if (!global.filePath)
                    global.filePath = new Strings();
                global.filePath->append(a);
            }
        }
    }

    if (global.params.addMain)
    {
        // a dummy name, we never actually look up this file
        files.push(const_cast<char*>(global.main_d));
    }

    // Create Modules
    Modules modules;
    modules.reserve(files.dim);
    for (unsigned i = 0; i < files.dim; i++)
    {   Identifier *id;
        const char *ext;
        const char *name;

        const char *p = static_cast<const char *>(files.data[i]);

        p = FileName::name(p);      // strip path
        ext = FileName::ext(p);
        if (ext)
        {
#if LDC_POSIX
            if (strcmp(ext, global.obj_ext) == 0 ||
                strcmp(ext, global.bc_ext) == 0)
#else
            if (Port::stricmp(ext, global.obj_ext) == 0 ||
                Port::stricmp(ext, global.obj_ext_alt) == 0 ||
                Port::stricmp(ext, global.bc_ext) == 0)
#endif
            {
                global.params.objfiles->push(static_cast<const char *>(files.data[i]));
                continue;
            }

#if LDC_POSIX
            if (strcmp(ext, "a") == 0)
#elif __MINGW32__
            if (Port::stricmp(ext, "a") == 0)
#else
            if (Port::stricmp(ext, "lib") == 0)
#endif
            {
                global.params.libfiles->push(static_cast<const char *>(files.data[i]));
                continue;
            }

            if (strcmp(ext, global.ddoc_ext) == 0)
            {
                global.params.ddocfiles->push(static_cast<const char *>(files.data[i]));
                continue;
            }

            if (FileName::equals(ext, global.json_ext))
            {
                global.params.doJsonGeneration = 1;
                global.params.jsonfilename = static_cast<const char *>(files.data[i]);
                continue;
            }

#if !LDC_POSIX
            if (Port::stricmp(ext, "res") == 0)
            {
                global.params.resfile = static_cast<const char *>(files.data[i]);
                continue;
            }

            if (Port::stricmp(ext, "def") == 0)
            {
                global.params.deffile = static_cast<const char *>(files.data[i]);
                continue;
            }

            if (Port::stricmp(ext, "exe") == 0)
            {
                global.params.exefile = static_cast<const char *>(files.data[i]);
                continue;
            }
#endif

            if (Port::stricmp(ext, global.mars_ext) == 0 ||
                Port::stricmp(ext, global.hdr_ext) == 0 ||
                FileName::equals(ext, "dd"))
            {
                ext--;          // skip onto '.'
                assert(*ext == '.');
                char *tmp = static_cast<char *>(mem.xmalloc((ext - p) + 1));
                memcpy(tmp, p, ext - p);
                tmp[ext - p] = 0;      // strip extension
                name = tmp;

                if (name[0] == 0 ||
                    strcmp(name, "..") == 0 ||
                    strcmp(name, ".") == 0)
                {
                    goto Linvalid;
                }
            }
            else
            {   error(Loc(), "unrecognized file extension %s\n", ext);
                fatal();
            }
        }
        else
        {   name = p;
            if (!*p)
            {
        Linvalid:
                error(Loc(), "invalid file name '%s'", static_cast<const char *>(files.data[i]));
                fatal();
            }
            name = p;
        }

        id = Identifier::idPool(name);
        Module *m = new Module(static_cast<const char *>(files.data[i]), id, global.params.doDocComments, global.params.doHdrGeneration);
        modules.push(m);
    }

    // Read files, parse them
    for (unsigned i = 0; i < modules.dim; i++)
    {
        Module *m = modules[i];
        if (global.params.verbose)
            fprintf(global.stdmsg, "parse     %s\n", m->toChars());
        if (!Module::rootModule)
            Module::rootModule = m;
        m->importedFrom = m;

        if (strcmp(m->srcfile->name->str, global.main_d) == 0)
        {
            static const char buf[] = "void main(){}";
            m->srcfile->setbuffer(const_cast<char *>(buf), sizeof(buf));
            m->srcfile->ref = 1;
        }
        else
        {
            m->read(Loc());
        }

        m->parse(global.params.doDocComments);
        m->buildTargetFiles(singleObj, createSharedLib || createStaticLib);
        m->deleteObjFile();
        if (m->isDocFile)
        {
            gendocfile(m);

            // Remove m from list of modules
            modules.remove(i);
            i--;
        }
    }
    if (global.errors)
        fatal();

    if (global.params.doHdrGeneration)
    {
        /* Generate 'header' import files.
         * Since 'header' import files must be independent of command
         * line switches and what else is imported, they are generated
         * before any semantic analysis.
         */
        for (unsigned i = 0; i < modules.dim; i++)
        {
            if (global.params.verbose)
                fprintf(global.stdmsg, "import    %s\n", modules[i]->toChars());
            genhdrfile(modules[i]);
        }
    }
    if (global.errors)
        fatal();

    // load all unconditional imports for better symbol resolving
    for (unsigned i = 0; i < modules.dim; i++)
    {
       if (global.params.verbose)
           fprintf(global.stdmsg, "importall %s\n", modules[i]->toChars());
       modules[i]->importAll(0);
    }
    if (global.errors)
       fatal();

    // Do semantic analysis
    for (unsigned i = 0; i < modules.dim; i++)
    {
        if (global.params.verbose)
            fprintf(global.stdmsg, "semantic  %s\n", modules[i]->toChars());
        modules[i]->semantic();
    }
    if (global.errors)
        fatal();

    Module::dprogress = 1;
    Module::runDeferredSemantic();

    // Do pass 2 semantic analysis
    for (unsigned i = 0; i < modules.dim; i++)
    {
        if (global.params.verbose)
            fprintf(global.stdmsg, "semantic2 %s\n", modules[i]->toChars());
        modules[i]->semantic2();
    }
    if (global.errors)
        fatal();

    // Do pass 3 semantic analysis
    for (unsigned i = 0; i < modules.dim; i++)
    {
        if (global.params.verbose)
            fprintf(global.stdmsg, "semantic3 %s\n", modules[i]->toChars());
        modules[i]->semantic3();
    }
    if (global.errors)
        fatal();

    Module::runDeferredSemantic3();

    if (global.errors || global.warnings)
        fatal();

    // Now that we analyzed all modules, write the module dependency file if
    // the user requested it.
    if (global.params.moduleDepsFile != NULL)
    {
        File deps(global.params.moduleDepsFile);
        OutBuffer* ob = global.params.moduleDeps;
        deps.setbuffer(static_cast<void*>(ob->data), ob->offset);
        deps.write();
    }

    // Generate one or more object/IR/bitcode files.
    if (global.params.obj && !modules.empty())
    {
        ldc::CodeGenerator cg(llvm::getGlobalContext(), singleObj);

        for (unsigned i = 0; i < modules.dim; i++)
        {
            Module * const m = modules[i];
            if (global.params.verbose)
                fprintf(global.stdmsg, "code      %s\n", m->toChars());

            cg.emit(m);

            if (global.errors)
                fatal();
        }
    }

    // Generate DDoc output files.
    if (global.params.doDocComments)
    {
        for (unsigned i = 0; i < modules.dim; i++)
        {
            gendocfile(modules[i]);
        }
    }

    // Generate the AST-describing JSON file.
    if (global.params.doJsonGeneration)
        emitJson(modules);

    LLVM_D_FreeRuntime();
    llvm::llvm_shutdown();

    if (global.errors)
        fatal();

    // Finally, produce the final executable/archive and run it, if we are
    // supposed to.
    int status = EXIT_SUCCESS;
    if (!global.params.objfiles->dim)
    {
        if (global.params.link)
            error(Loc(), "no object files to link");
        else if (createStaticLib)
            error(Loc(), "no object files");
    }
    else
    {
        if (global.params.link)
            status = linkObjToBinary(createSharedLib);
        else if (createStaticLib)
            createStaticLibrary();

        if (global.params.run && status == EXIT_SUCCESS)
        {
            status = runExecutable();

            /// Delete .obj files and .exe file.
            for (unsigned i = 0; i < modules.dim; i++)
            {
                modules[i]->deleteObjFile();
            }
            deleteExecutable();
        }
    }

    return status;
}
Exemple #8
0
/// Parses switches from the command line, any response files and the global
/// config file and sets up global.params accordingly.
///
/// Returns a list of source file names.
static void parseCommandLine(int argc, char **argv, Strings &sourceFiles, bool &helpOnly) {
#if _WIN32
    char buf[MAX_PATH];
    GetModuleFileName(NULL, buf, MAX_PATH);
    const char* argv0 = &buf[0];
    // FIXME: We cannot set params.argv0 here, as we would escape a stack
    // reference, but it is unused anyway.
    global.params.argv0 = NULL;
#else
    const char* argv0 = global.params.argv0 = argv[0];
#endif

    // Set some default values.
    global.params.useSwitchError = 1;
    global.params.useArrayBounds = 2;
    global.params.color = isConsoleColorSupported();

    global.params.linkswitches = new Strings();
    global.params.libfiles = new Strings();
    global.params.objfiles = new Strings();
    global.params.ddocfiles = new Strings();

    global.params.moduleDeps = NULL;
    global.params.moduleDepsFile = NULL;

    // Build combined list of command line arguments.
    std::vector<const char*> final_args;
    final_args.push_back(argv[0]);

    ConfigFile cfg_file;
    // just ignore errors for now, they are still printed
    cfg_file.read(argv0, (void*)main, "ldc2.conf");
    final_args.insert(final_args.end(), cfg_file.switches_begin(), cfg_file.switches_end());

    final_args.insert(final_args.end(), &argv[1], &argv[argc]);

    cl::SetVersionPrinter(&printVersion);
#if LDC_LLVM_VER >= 303
    hideLLVMOptions();
#endif
    cl::ParseCommandLineOptions(final_args.size(), const_cast<char**>(&final_args[0]),
        "LDC - the LLVM D compiler\n"
#if LDC_LLVM_VER < 302
        , true
#endif
    );

    helpOnly = mCPU == "help" ||
        (std::find(mAttrs.begin(), mAttrs.end(), "help") != mAttrs.end());

    // Print some information if -v was passed
    // - path to compiler binary
    // - version number
    // - used config file
    if (global.params.verbose) {
        fprintf(global.stdmsg, "binary    %s\n", llvm::sys::fs::getMainExecutable(argv0, (void*)main).c_str());
        fprintf(global.stdmsg, "version   %s (DMD %s, LLVM %s)\n", global.ldc_version, global.version, global.llvm_version);
        const std::string& path = cfg_file.path();
        if (!path.empty())
            fprintf(global.stdmsg, "config    %s\n", path.c_str());
    }

    // Negated options
    global.params.link = !compileOnly;
    global.params.obj = !dontWriteObj;
    global.params.useInlineAsm = !noAsm;

    // String options: std::string --> char*
    initFromString(global.params.objname, objectFile);
    initFromString(global.params.objdir, objectDir);

    initFromString(global.params.docdir, ddocDir);
    initFromString(global.params.docname, ddocFile);
    global.params.doDocComments |=
        global.params.docdir || global.params.docname;

    initFromString(global.params.jsonfilename, jsonFile);
    if (global.params.jsonfilename)
        global.params.doJsonGeneration = true;

    initFromString(global.params.hdrdir, hdrDir);
    initFromString(global.params.hdrname, hdrFile);
    global.params.doHdrGeneration |=
        global.params.hdrdir || global.params.hdrname;

    initFromString(global.params.moduleDepsFile, moduleDepsFile);
    if (global.params.moduleDepsFile != NULL)
    {
         global.params.moduleDeps = new OutBuffer;
    }

    processVersions(debugArgs, "debug",
        DebugCondition::setGlobalLevel,
        DebugCondition::addGlobalIdent);
    processVersions(versions, "version",
        VersionCondition::setGlobalLevel,
        VersionCondition::addGlobalIdent);

    global.params.output_o =
        (opts::output_o == cl::BOU_UNSET
            && !(opts::output_bc || opts::output_ll || opts::output_s))
        ? OUTPUTFLAGdefault
        : opts::output_o == cl::BOU_TRUE
            ? OUTPUTFLAGset
            : OUTPUTFLAGno;
    global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno;
    global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno;
    global.params.output_s  = opts::output_s  ? OUTPUTFLAGset : OUTPUTFLAGno;

    global.params.cov = (global.params.covPercent <= 100);

    templateLinkage =
        opts::linkonceTemplates ? LLGlobalValue::LinkOnceODRLinkage
                                : LLGlobalValue::WeakODRLinkage;

    if (global.params.run || !runargs.empty()) {
        // FIXME: how to properly detect the presence of a PositionalEatsArgs
        // option without parameters? We want to emit an error in that case...
        // You'd think getNumOccurrences would do it, but it just returns the
        // number of parameters)
        // NOTE: Hacked around it by detecting -run in getenv_setargv(), where
        // we're looking for it anyway, and pre-setting the flag...
        global.params.run = true;
        if (!runargs.empty()) {
            char const * name = runargs[0].c_str();
            char const * ext = FileName::ext(name);
            if (ext && FileName::equals(ext, "d") == 0 &&
                FileName::equals(ext, "di") == 0) {
                error(Loc(), "-run must be followed by a source file, not '%s'", name);
            }

            sourceFiles.push(mem.xstrdup(name));
            runargs.erase(runargs.begin());
        } else {
            global.params.run = false;
            error(Loc(), "Expected at least one argument to '-run'\n");
        }
    }

    sourceFiles.reserve(fileList.size());
    typedef std::vector<std::string>::iterator It;
    for(It I = fileList.begin(), E = fileList.end(); I != E; ++I)
        if (!I->empty())
            sourceFiles.push(mem.xstrdup(I->c_str()));

    if (noDefaultLib)
    {
        deprecation(Loc(), "-nodefaultlib is deprecated, as "
            "-defaultlib/-debuglib now override the existing list instead of "
            "appending to it. Please use the latter instead.");
    }
    else
    {
        // Parse comma-separated default library list.
        std::stringstream libNames(
            global.params.symdebug ? debugLib : defaultLib);
        while (libNames.good())
        {
            std::string lib;
            std::getline(libNames, lib, ',');
            if (lib.empty()) continue;

            char *arg = static_cast<char *>(mem.xmalloc(lib.size() + 3));
            strcpy(arg, "-l");
            strcpy(arg+2, lib.c_str());
            global.params.linkswitches->push(arg);
        }
    }

    if (global.params.useUnitTests)
        global.params.useAssert = 1;

    // -release downgrades default bounds checking level to BC_SafeOnly (only for safe functions).
    global.params.useArrayBounds = opts::nonSafeBoundsChecks ? opts::BC_On : opts::BC_SafeOnly;
    if (opts::boundsCheck != opts::BC_Default)
        global.params.useArrayBounds = opts::boundsCheck;

    // LDC output determination

    // if we don't link, autodetect target from extension
    if(!global.params.link && !createStaticLib && global.params.objname) {
        const char *ext = FileName::ext(global.params.objname);
        bool autofound = false;
        if (!ext) {
            // keep things as they are
        } else if (strcmp(ext, global.ll_ext) == 0) {
            global.params.output_ll = OUTPUTFLAGset;
            autofound = true;
        } else if (strcmp(ext, global.bc_ext) == 0) {
            global.params.output_bc = OUTPUTFLAGset;
            autofound = true;
        } else if (strcmp(ext, global.s_ext) == 0) {
            global.params.output_s = OUTPUTFLAGset;
            autofound = true;
        } else if (strcmp(ext, global.obj_ext) == 0 || strcmp(ext, global.obj_ext_alt) == 0) {
            global.params.output_o = OUTPUTFLAGset;
            autofound = true;
        } else {
            // append dot, so forceExt won't change existing name even if it contains dots
            size_t len = strlen(global.params.objname);
            char* s = static_cast<char *>(mem.xmalloc(len + 1 + 1));
            memcpy(s, global.params.objname, len);
            s[len] = '.';
            s[len+1] = 0;
            global.params.objname = s;

        }
        if(autofound && global.params.output_o == OUTPUTFLAGdefault)
            global.params.output_o = OUTPUTFLAGno;
    }

    // only link if possible
    if (!global.params.obj || !global.params.output_o || createStaticLib)
        global.params.link = 0;

    if (createStaticLib && createSharedLib)
        error(Loc(), "-lib and -shared switches cannot be used together");

    if (createSharedLib && mRelocModel == llvm::Reloc::Default)
        mRelocModel = llvm::Reloc::PIC_;

    if (global.params.link && !createSharedLib)
    {
        global.params.exefile = global.params.objname;
        if (sourceFiles.dim > 1)
            global.params.objname = NULL;
    }
    else if (global.params.run)
    {
        error(Loc(), "flags conflict with -run");
    }
    else if (global.params.objname && sourceFiles.dim > 1) {
        if (!(createStaticLib || createSharedLib) && !singleObj)
        {
            error(Loc(), "multiple source files, but only one .obj name");
        }
    }

    if (soname.getNumOccurrences() > 0 && !createSharedLib) {
        error(Loc(), "-soname can be used only when building a shared library");
    }
}
Exemple #9
0
int runLINK()
{
#if _WIN32
    if (global.params.is64bit)
    {
        OutBuffer cmdbuf;

        cmdbuf.writestring("/NOLOGO ");

        for (size_t i = 0; i < global.params.objfiles->dim; i++)
        {
            if (i)
                cmdbuf.writeByte(' ');
            const char *p = (*global.params.objfiles)[i];
            const char *basename = FileName::removeExt(FileName::name(p));
            const char *ext = FileName::ext(p);
            if (ext && !strchr(basename, '.'))
            {
                // Write name sans extension (but not if a double extension)
                writeFilename(&cmdbuf, p, ext - p - 1);
            }
            else
                writeFilename(&cmdbuf, p);
            FileName::free(basename);
        }

        if (global.params.resfile)
        {
            cmdbuf.writeByte(' ');
            writeFilename(&cmdbuf, global.params.resfile);
        }

        cmdbuf.writeByte(' ');
        if (global.params.exefile)
        {   cmdbuf.writestring("/OUT:");
            writeFilename(&cmdbuf, global.params.exefile);
        }
        else
        {   /* Generate exe file name from first obj name.
             * No need to add it to cmdbuf because the linker will default to it.
             */
            const char *n = (*global.params.objfiles)[0];
            n = FileName::name(n);
            global.params.exefile = (char *)FileName::forceExt(n, "exe");
        }

        // Make sure path to exe file exists
        ensurePathToNameExists(Loc(), global.params.exefile);

        cmdbuf.writeByte(' ');
        if (global.params.mapfile)
        {   cmdbuf.writestring("/MAP:");
            writeFilename(&cmdbuf, global.params.mapfile);
        }
        else if (global.params.map)
        {
            const char *fn = FileName::forceExt(global.params.exefile, "map");

            const char *path = FileName::path(global.params.exefile);
            const char *p;
            if (path[0] == '\0')
                p = FileName::combine(global.params.objdir, fn);
            else
                p = fn;

            cmdbuf.writestring("/MAP:");
            writeFilename(&cmdbuf, p);
        }

        for (size_t i = 0; i < global.params.libfiles->dim; i++)
        {
            cmdbuf.writeByte(' ');
            cmdbuf.writestring("/DEFAULTLIB:");
            writeFilename(&cmdbuf, (*global.params.libfiles)[i]);
        }

        if (global.params.deffile)
        {
            cmdbuf.writeByte(' ');
            cmdbuf.writestring("/DEF:");
            writeFilename(&cmdbuf, global.params.deffile);
        }

        if (global.params.symdebug)
        {
            cmdbuf.writeByte(' ');
            cmdbuf.writestring("/DEBUG");

            // in release mode we need to reactivate /OPT:REF after /DEBUG
            if (global.params.release)
                cmdbuf.writestring(" /OPT:REF");
        }

        if (global.params.dll)
        {
            cmdbuf.writeByte(' ');
            cmdbuf.writestring("/DLL");
        }

        for (size_t i = 0; i < global.params.linkswitches->dim; i++)
        {
            cmdbuf.writeByte(' ');
            cmdbuf.writestring((*global.params.linkswitches)[i]);
        }

        /* Append the path to the VC lib files, and then the SDK lib files
         */
        const char *vcinstalldir = getenv("VCINSTALLDIR");
        if (vcinstalldir)
        {   cmdbuf.writestring(" \"/LIBPATH:");
            cmdbuf.writestring(vcinstalldir);
            cmdbuf.writestring("lib\\amd64\"");
        }

        const char *windowssdkdir = getenv("WindowsSdkDir");
        if (windowssdkdir)
        {   cmdbuf.writestring(" \"/LIBPATH:");
            cmdbuf.writestring(windowssdkdir);
            cmdbuf.writestring("lib\\x64\"");
        }

        char *p = cmdbuf.peekString();

        const char *lnkfilename = NULL;
        size_t plen = strlen(p);
        if (plen > 7000)
        {
            lnkfilename = FileName::forceExt(global.params.exefile, "lnk");
            File flnk(lnkfilename);
            flnk.setbuffer(p, plen);
            flnk.ref = 1;
            if (flnk.write())
                error(Loc(), "error writing file %s", lnkfilename);
            if (strlen(lnkfilename) < plen)
                sprintf(p, "@%s", lnkfilename);
        }

        const char *linkcmd = getenv("LINKCMD64");
        if (!linkcmd)
            linkcmd = getenv("LINKCMD"); // backward compatible
        if (!linkcmd)
        {
            if (vcinstalldir)
            {
                OutBuffer linkcmdbuf;
                linkcmdbuf.writestring(vcinstalldir);
                linkcmdbuf.writestring("bin\\amd64\\link");
                linkcmd = linkcmdbuf.extractString();
            }
            else
                linkcmd = "link";
        }
        int status = executecmd(linkcmd, p);
        if (lnkfilename)
        {
            remove(lnkfilename);
            FileName::free(lnkfilename);
        }
        return status;
    }
    else
    {
        OutBuffer cmdbuf;

        global.params.libfiles->push("user32");
        global.params.libfiles->push("kernel32");

        for (size_t i = 0; i < global.params.objfiles->dim; i++)
        {
            if (i)
                cmdbuf.writeByte('+');
            const char *p = (*global.params.objfiles)[i];
            const char *basename = FileName::removeExt(FileName::name(p));
            const char *ext = FileName::ext(p);
            if (ext && !strchr(basename, '.'))
            {
                // Write name sans extension (but not if a double extension)
                writeFilename(&cmdbuf, p, ext - p - 1);
            }
            else
                writeFilename(&cmdbuf, p);
            FileName::free(basename);
        }
        cmdbuf.writeByte(',');
        if (global.params.exefile)
            writeFilename(&cmdbuf, global.params.exefile);
        else
        {   /* Generate exe file name from first obj name.
             * No need to add it to cmdbuf because the linker will default to it.
             */
            const char *n = (*global.params.objfiles)[0];
            n = FileName::name(n);
            global.params.exefile = (char *)FileName::forceExt(n, "exe");
        }

        // Make sure path to exe file exists
        ensurePathToNameExists(Loc(), global.params.exefile);

        cmdbuf.writeByte(',');
        if (global.params.mapfile)
            writeFilename(&cmdbuf, global.params.mapfile);
        else if (global.params.map)
        {
            const char *fn = FileName::forceExt(global.params.exefile, "map");

            const char *path = FileName::path(global.params.exefile);
            const char *p;
            if (path[0] == '\0')
                p = FileName::combine(global.params.objdir, fn);
            else
                p = fn;

            writeFilename(&cmdbuf, p);
        }
        else
            cmdbuf.writestring("nul");
        cmdbuf.writeByte(',');

        for (size_t i = 0; i < global.params.libfiles->dim; i++)
        {
            if (i)
                cmdbuf.writeByte('+');
            writeFilename(&cmdbuf, (*global.params.libfiles)[i]);
        }

        if (global.params.deffile)
        {
            cmdbuf.writeByte(',');
            writeFilename(&cmdbuf, global.params.deffile);
        }

        /* Eliminate unnecessary trailing commas    */
        while (1)
        {   size_t i = cmdbuf.offset;
            if (!i || cmdbuf.data[i - 1] != ',')
                break;
            cmdbuf.offset--;
        }

        if (global.params.resfile)
        {
            cmdbuf.writestring("/RC:");
            writeFilename(&cmdbuf, global.params.resfile);
        }

        if (global.params.map || global.params.mapfile)
            cmdbuf.writestring("/m");

#if 0
        if (debuginfo)
            cmdbuf.writestring("/li");
        if (codeview)
        {
            cmdbuf.writestring("/co");
            if (codeview3)
                cmdbuf.writestring(":3");
        }
#else
        if (global.params.symdebug)
            cmdbuf.writestring("/co");
#endif

        cmdbuf.writestring("/noi");
        for (size_t i = 0; i < global.params.linkswitches->dim; i++)
        {
            cmdbuf.writestring((*global.params.linkswitches)[i]);
        }
        cmdbuf.writeByte(';');

        char *p = cmdbuf.peekString();

        const char *lnkfilename = NULL;
        size_t plen = strlen(p);
        if (plen > 7000)
        {
            lnkfilename = FileName::forceExt(global.params.exefile, "lnk");
            File flnk(lnkfilename);
            flnk.setbuffer(p, plen);
            flnk.ref = 1;
            if (flnk.write())
                error(Loc(), "error writing file %s", lnkfilename);
            if (strlen(lnkfilename) < plen)
                sprintf(p, "@%s", lnkfilename);
        }

        const char *linkcmd = getenv("LINKCMD");
        if (!linkcmd)
            linkcmd = "link";
        int status = executecmd(linkcmd, p);
        if (lnkfilename)
        {
            remove(lnkfilename);
            FileName::free(lnkfilename);
        }
        return status;
    }
#elif __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
    pid_t childpid;
    int status;

    // Build argv[]
    Strings argv;

    const char *cc = getenv("CC");
    if (!cc)
        cc = "gcc";
    argv.push(cc);
    argv.insert(1, global.params.objfiles);

#if __APPLE__
    // If we are on Mac OS X and linking a dynamic library,
    // add the "-dynamiclib" flag
    if (global.params.dll)
        argv.push("-dynamiclib");
#elif __linux__ || __FreeBSD__ || __OpenBSD__ || __sun
    if (global.params.dll)
        argv.push("-shared");
#endif

    // None of that a.out stuff. Use explicit exe file name, or
    // generate one from name of first source file.
    argv.push("-o");
    if (global.params.exefile)
    {
        argv.push(global.params.exefile);
    }
    else if (global.params.run)
    {
#if 1
        char name[L_tmpnam + 14 + 1];
        strcpy(name, P_tmpdir);
        strcat(name, "/dmd_runXXXXXX");
        int fd = mkstemp(name);
        if (fd == -1)
        {   error(Loc(), "error creating temporary file");
            return 1;
        }
        else
            close(fd);
        global.params.exefile = mem.strdup(name);
        argv.push(global.params.exefile);
#else
        /* The use of tmpnam raises the issue of "is this a security hole"?
         * The hole is that after tmpnam and before the file is opened,
         * the attacker modifies the file system to get control of the
         * file with that name. I do not know if this is an issue in
         * this context.
         * We cannot just replace it with mkstemp, because this name is
         * passed to the linker that actually opens the file and writes to it.
         */
        char s[L_tmpnam + 1];
        char *n = tmpnam(s);
        global.params.exefile = mem.strdup(n);
        argv.push(global.params.exefile);
#endif
    }
    else
    {   // Generate exe file name from first obj name
        const char *n = (*global.params.objfiles)[0];
        char *ex;

        n = FileName::name(n);
        const char *e = FileName::ext(n);
        if (e)
        {
            e--;                        // back up over '.'
            ex = (char *)mem.malloc(e - n + 1);
            memcpy(ex, n, e - n);
            ex[e - n] = 0;
            // If generating dll then force dll extension
            if (global.params.dll)
                ex = (char *)FileName::forceExt(ex, global.dll_ext);
        }
        else
            ex = (char *)"a.out";       // no extension, so give up
        argv.push(ex);
        global.params.exefile = ex;
    }

    // Make sure path to exe file exists
    ensurePathToNameExists(Loc(), global.params.exefile);

    if (global.params.symdebug)
        argv.push("-g");

    if (global.params.is64bit)
        argv.push("-m64");
    else
        argv.push("-m32");

    if (global.params.map || global.params.mapfile)
    {
        argv.push("-Xlinker");
#if __APPLE__
        argv.push("-map");
#else
        argv.push("-Map");
#endif
        if (!global.params.mapfile)
        {
            const char *fn = FileName::forceExt(global.params.exefile, "map");

            const char *path = FileName::path(global.params.exefile);
            const char *p;
            if (path[0] == '\0')
                p = FileName::combine(global.params.objdir, fn);
            else
                p = fn;

            global.params.mapfile = (char *)p;
        }
        argv.push("-Xlinker");
        argv.push(global.params.mapfile);
    }

    /* This switch enables what is known as 'smart linking'
     * in the Windows world, where unreferenced sections
     * are removed from the executable. It eliminates unreferenced
     * functions, essentially making a 'library' out of a module.
     * Although it is documented to work with ld version 2.13,
     * in practice it does not, but just seems to be ignored.
     * Thomas Kuehne has verified that it works with ld 2.16.1.
     */
#if __linux__
    /* Only works on linux because the linkers shipped with other
     * OSes don't yet support this flag.
     */
    argv.push("-Xlinker");
    argv.push("--gc-sections");
#endif

    for (size_t i = 0; i < global.params.linkswitches->dim; i++)
    {   const char *p = (*global.params.linkswitches)[i];
        if (!p || !p[0] || !(p[0] == '-' && (p[1] == 'l' || p[1] == 'L')))
            // Don't need -Xlinker if switch starts with -l or -L.
            // Eliding -Xlinker is significant for -L since it allows our paths
            // to take precedence over gcc defaults.
            argv.push("-Xlinker");
        argv.push(p);
    }

    /* Add each library, prefixing it with "-l".
     * The order of libraries passed is:
     *  1. any libraries passed with -L command line switch
     *  2. libraries specified on the command line
     *  3. libraries specified by pragma(lib), which were appended
     *     to global.params.libfiles.
     *  4. standard libraries.
     */
    for (size_t i = 0; i < global.params.libfiles->dim; i++)
    {   const char *p = (*global.params.libfiles)[i];
        size_t plen = strlen(p);
        if (plen > 2 && p[plen - 2] == '.' && p[plen -1] == 'a')
            argv.push(p);
        else
        {
            char *s = (char *)mem.malloc(plen + 3);
            s[0] = '-';
            s[1] = 'l';
            memcpy(s + 2, p, plen + 1);
            argv.push(s);
        }
    }

    for (size_t i = 0; i < global.params.dllfiles->dim; i++)
    {
        const char *p = (*global.params.dllfiles)[i];
        argv.push(p);
    }

    /* Standard libraries must go after user specified libraries
     * passed with -l.
     */
    const char *libname = (global.params.symdebug)
                                ? global.params.debuglibname
                                : global.params.defaultlibname;
    size_t slen = strlen(libname);
    if (slen)
    {
        char *buf = (char *)malloc(3 + slen + 1);
        strcpy(buf, "-l");
        /* Use "-l:libname.a" if the library name is complete
         */
        if (slen > 3 + 2 &&
            memcmp(libname, "lib", 3) == 0 &&
            (memcmp(libname + slen - 2, ".a", 2) == 0 ||
             memcmp(libname + slen - 3, ".so", 3) == 0)
           )
        {
            strcat(buf, ":");
        }
        strcat(buf, libname);
        argv.push(buf);             // turns into /usr/lib/libphobos2.a
    }

#ifdef __sun
    argv.push("-mt");
#endif

//    argv.push("-ldruntime");
    argv.push("-lpthread");
    argv.push("-lm");
#if __linux__
    // Changes in ld for Ubuntu 11.10 require this to appear after phobos2
    argv.push("-lrt");
#endif

    if (global.params.verbose)
    {
        // Print it
        for (size_t i = 0; i < argv.dim; i++)
            fprintf(global.stdmsg, "%s ", argv[i]);
        fprintf(global.stdmsg, "\n");
    }

    argv.push(NULL);

    // set up pipes
    int fds[2];

    if (pipe(fds) == -1)
    {
        perror("Unable to create pipe to linker");
        return -1;
    }

    childpid = fork();
    if (childpid == 0)
    {
        // pipe linker stderr to fds[0]
        dup2(fds[1], STDERR_FILENO);
        close(fds[0]);

        execvp(argv[0], (char **)argv.tdata());
        perror(argv[0]);           // failed to execute
        return -1;
    }
    else if (childpid == -1)
    {
        perror("Unable to fork");
        return -1;
    }
    close(fds[1]);
    const int nme = findNoMainError(fds[0]);
    waitpid(childpid, &status, 0);

    if (WIFEXITED(status))
    {
        status = WEXITSTATUS(status);
        if (status)
        {
            if (nme == -1)
            {
                perror("Error with the linker pipe");
                return -1;
            }
            else
            {
                printf("--- errorlevel %d\n", status);
                if (nme == 1) error(Loc(), "no main function specified");
            }
        }
    }
    else if (WIFSIGNALED(status))
    {
        printf("--- killed by signal %d\n", WTERMSIG(status));
        status = 1;
    }
    return status;
#else
    printf ("Linking is not yet supported for this version of DMD.\n");
    return -1;
#endif
}
Exemple #10
0
/// Parses switches from the command line, any response files and the global
/// config file and sets up global.params accordingly.
///
/// Returns a list of source file names.
static void parseCommandLine(int argc, char **argv, Strings &sourceFiles,
                             bool &helpOnly) {
  global.params.argv0 = exe_path::getExePath().data();

  // Set some default values.
  global.params.useSwitchError = 1;
  global.params.color = isConsoleColorSupported();

  global.params.linkswitches = new Strings();
  global.params.libfiles = new Strings();
  global.params.objfiles = new Strings();
  global.params.ddocfiles = new Strings();

  global.params.moduleDeps = nullptr;
  global.params.moduleDepsFile = nullptr;

  // Build combined list of command line arguments.
  std::vector<const char *> final_args;
  final_args.push_back(argv[0]);

  ConfigFile cfg_file;
  const char *explicitConfFile = tryGetExplicitConfFile(argc, argv);
  // just ignore errors for now, they are still printed
  cfg_file.read(explicitConfFile);
  final_args.insert(final_args.end(), cfg_file.switches_begin(),
                    cfg_file.switches_end());

  final_args.insert(final_args.end(), &argv[1], &argv[argc]);

  cl::SetVersionPrinter(&printVersion);
  hideLLVMOptions();
  cl::ParseCommandLineOptions(final_args.size(),
                              const_cast<char **>(final_args.data()),
                              "LDC - the LLVM D compiler\n");

  helpOnly = mCPU == "help" ||
             (std::find(mAttrs.begin(), mAttrs.end(), "help") != mAttrs.end());

  // Print some information if -v was passed
  // - path to compiler binary
  // - version number
  // - used config file
  if (global.params.verbose) {
    fprintf(global.stdmsg, "binary    %s\n", exe_path::getExePath().c_str());
    fprintf(global.stdmsg, "version   %s (DMD %s, LLVM %s)\n",
            global.ldc_version, global.version, global.llvm_version);
    const std::string &path = cfg_file.path();
    if (!path.empty()) {
      fprintf(global.stdmsg, "config    %s\n", path.c_str());
    }
  }

  // Negated options
  global.params.link = !compileOnly;
  global.params.obj = !dontWriteObj;
  global.params.useInlineAsm = !noAsm;

  // String options: std::string --> char*
  initFromString(global.params.objname, objectFile);
  initFromString(global.params.objdir, objectDir);

  initFromString(global.params.docdir, ddocDir);
  initFromString(global.params.docname, ddocFile);
  global.params.doDocComments |= global.params.docdir || global.params.docname;

  initFromString(global.params.jsonfilename, jsonFile);
  if (global.params.jsonfilename) {
    global.params.doJsonGeneration = true;
  }

  initFromString(global.params.hdrdir, hdrDir);
  initFromString(global.params.hdrname, hdrFile);
  global.params.doHdrGeneration |=
      global.params.hdrdir || global.params.hdrname;

  initFromString(global.params.moduleDepsFile, moduleDepsFile);
  if (global.params.moduleDepsFile != nullptr) {
    global.params.moduleDeps = new OutBuffer;
  }

  processVersions(debugArgs, "debug", DebugCondition::setGlobalLevel,
                  DebugCondition::addGlobalIdent);
  processVersions(versions, "version", VersionCondition::setGlobalLevel,
                  VersionCondition::addGlobalIdent);

  processTransitions(transitions);

  global.params.output_o =
      (opts::output_o == cl::BOU_UNSET &&
       !(opts::output_bc || opts::output_ll || opts::output_s))
          ? OUTPUTFLAGdefault
          : opts::output_o == cl::BOU_TRUE ? OUTPUTFLAGset : OUTPUTFLAGno;
  global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno;
  global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno;
  global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno;

  global.params.cov = (global.params.covPercent <= 100);

  templateLinkage = opts::linkonceTemplates ? LLGlobalValue::LinkOnceODRLinkage
                                            : LLGlobalValue::WeakODRLinkage;

  if (global.params.run || !runargs.empty()) {
    // FIXME: how to properly detect the presence of a PositionalEatsArgs
    // option without parameters? We want to emit an error in that case...
    // You'd think getNumOccurrences would do it, but it just returns the
    // number of parameters)
    // NOTE: Hacked around it by detecting -run in getenv_setargv(), where
    // we're looking for it anyway, and pre-setting the flag...
    global.params.run = true;
    if (!runargs.empty()) {
      char const *name = runargs[0].c_str();
      char const *ext = FileName::ext(name);
      if (ext && FileName::equals(ext, "d") == 0 &&
          FileName::equals(ext, "di") == 0) {
        error(Loc(), "-run must be followed by a source file, not '%s'", name);
      }

      sourceFiles.push(mem.xstrdup(name));
      runargs.erase(runargs.begin());
    } else {
      global.params.run = false;
      error(Loc(), "Expected at least one argument to '-run'\n");
    }
  }

  sourceFiles.reserve(fileList.size());
  for (const auto &file : fileList) {
    if (!file.empty()) {
      char *copy = mem.xstrdup(file.c_str());
#ifdef _WIN32
      std::replace(copy, copy + file.length(), '/', '\\');
#endif
      sourceFiles.push(copy);
    }
  }

  if (noDefaultLib) {
    deprecation(
        Loc(),
        "-nodefaultlib is deprecated, as "
        "-defaultlib/-debuglib now override the existing list instead of "
        "appending to it. Please use the latter instead.");
  } else {
    // Parse comma-separated default library list.
    std::stringstream libNames(linkDebugLib ? debugLib : defaultLib);
    while (libNames.good()) {
      std::string lib;
      std::getline(libNames, lib, ',');
      if (lib.empty()) {
        continue;
      }

      char *arg = static_cast<char *>(mem.xmalloc(lib.size() + 3));
      strcpy(arg, "-l");
      strcpy(arg + 2, lib.c_str());
      global.params.linkswitches->push(arg);
    }
  }

  if (global.params.useUnitTests) {
    global.params.useAssert = 1;
  }

  // -release downgrades default bounds checking level to BOUNDSCHECKsafeonly
  // (only for safe functions).
  global.params.useArrayBounds =
      opts::nonSafeBoundsChecks ? BOUNDSCHECKon : BOUNDSCHECKsafeonly;
  if (opts::boundsCheck != BOUNDSCHECKdefault) {
    global.params.useArrayBounds = opts::boundsCheck;
  }

  // LDC output determination

  // if we don't link, autodetect target from extension
  if (!global.params.link && !createStaticLib && global.params.objname) {
    const char *ext = FileName::ext(global.params.objname);
    bool autofound = false;
    if (!ext) {
      // keep things as they are
    } else if (strcmp(ext, global.ll_ext) == 0) {
      global.params.output_ll = OUTPUTFLAGset;
      autofound = true;
    } else if (strcmp(ext, global.bc_ext) == 0) {
      global.params.output_bc = OUTPUTFLAGset;
      autofound = true;
    } else if (strcmp(ext, global.s_ext) == 0) {
      global.params.output_s = OUTPUTFLAGset;
      autofound = true;
    } else if (strcmp(ext, global.obj_ext) == 0 ||
               strcmp(ext, global.obj_ext_alt) == 0) {
      global.params.output_o = OUTPUTFLAGset;
      autofound = true;
    } else {
      // append dot, so forceExt won't change existing name even if it contains
      // dots
      size_t len = strlen(global.params.objname);
      char *s = static_cast<char *>(mem.xmalloc(len + 1 + 1));
      memcpy(s, global.params.objname, len);
      s[len] = '.';
      s[len + 1] = 0;
      global.params.objname = s;
    }
    if (autofound && global.params.output_o == OUTPUTFLAGdefault) {
      global.params.output_o = OUTPUTFLAGno;
    }
  }

  // only link if possible
  if (!global.params.obj || !global.params.output_o || createStaticLib) {
    global.params.link = 0;
  }

  if (createStaticLib && createSharedLib) {
    error(Loc(), "-lib and -shared switches cannot be used together");
  }

#if LDC_LLVM_VER >= 309
  if (createSharedLib && !mRelocModel.getNumOccurrences()) {
#else
  if (createSharedLib && mRelocModel == llvm::Reloc::Default) {
#endif
    mRelocModel = llvm::Reloc::PIC_;
  }

  if (global.params.link && !createSharedLib) {
    global.params.exefile = global.params.objname;
    if (sourceFiles.dim > 1) {
      global.params.objname = nullptr;
    }
  } else if (global.params.run) {
    error(Loc(), "flags conflict with -run");
  } else if (global.params.objname && sourceFiles.dim > 1) {
    if (!(createStaticLib || createSharedLib) && !singleObj) {
      error(Loc(), "multiple source files, but only one .obj name");
    }
  }

  if (soname.getNumOccurrences() > 0 && !createSharedLib) {
    error(Loc(), "-soname can be used only when building a shared library");
  }
}

static void initializePasses() {
  using namespace llvm;
  // Initialize passes
  PassRegistry &Registry = *PassRegistry::getPassRegistry();
  initializeCore(Registry);
  initializeTransformUtils(Registry);
  initializeScalarOpts(Registry);
  initializeObjCARCOpts(Registry);
  initializeVectorization(Registry);
  initializeInstCombine(Registry);
  initializeIPO(Registry);
  initializeInstrumentation(Registry);
  initializeAnalysis(Registry);
  initializeCodeGen(Registry);
#if LDC_LLVM_VER >= 309
  initializeGlobalISel(Registry);
#endif
  initializeTarget(Registry);

  // Initialize passes not included above
#if LDC_LLVM_VER < 306
  initializeDebugIRPass(Registry);
#endif
#if LDC_LLVM_VER < 308
  initializeIPA(Registry);
#endif
#if LDC_LLVM_VER >= 306
  initializeRewriteSymbolsPass(Registry);
#endif
#if LDC_LLVM_VER >= 307
  initializeSjLjEHPreparePass(Registry);
#endif
}

/// Register the MIPS ABI.
static void registerMipsABI() {
  switch (getMipsABI()) {
  case MipsABI::EABI:
    VersionCondition::addPredefinedGlobalIdent("MIPS_EABI");
    break;
  case MipsABI::O32:
    VersionCondition::addPredefinedGlobalIdent("MIPS_O32");
    break;
  case MipsABI::N32:
    VersionCondition::addPredefinedGlobalIdent("MIPS_N32");
    break;
  case MipsABI::N64:
    VersionCondition::addPredefinedGlobalIdent("MIPS_N64");
    break;
  case MipsABI::Unknown:
    break;
  }
}

/// Register the float ABI.
/// Also defines D_HardFloat or D_SoftFloat depending if FPU should be used
static void registerPredefinedFloatABI(const char *soft, const char *hard,
                                       const char *softfp = nullptr) {
// Use target floating point unit instead of s/w float routines
#if LDC_LLVM_VER >= 307
  // FIXME: This is a semantic change!
  bool useFPU = gTargetMachine->Options.FloatABIType == llvm::FloatABI::Hard;
#else
  bool useFPU = !gTargetMachine->Options.UseSoftFloat;
#endif
  VersionCondition::addPredefinedGlobalIdent(useFPU ? "D_HardFloat"
                                                    : "D_SoftFloat");

  if (gTargetMachine->Options.FloatABIType == llvm::FloatABI::Soft) {
    VersionCondition::addPredefinedGlobalIdent(useFPU && softfp ? softfp
                                                                : soft);
  } else if (gTargetMachine->Options.FloatABIType == llvm::FloatABI::Hard) {
    assert(useFPU && "Should be using the FPU if using float-abi=hard");
    VersionCondition::addPredefinedGlobalIdent(hard);
  } else {
    assert(0 && "FloatABIType neither Soft or Hard");
  }
}
Exemple #11
0
int main(int argc, char** argv)
{
    mem.init();                         // initialize storage allocator
    mem.setStackBottom(&argv);
#if _WIN32 && __DMC__
    mem.addroots((char *)&_xi_a, (char *)&_end);
#endif

    // stack trace on signals
    llvm::sys::PrintStackTraceOnErrorSignal();

    Strings files;
    char *p, *ext;
    Module *m;
    int status = EXIT_SUCCESS;

    // Set some default values
#if _WIN32
    char buf[MAX_PATH];
    GetModuleFileName(NULL, buf, MAX_PATH);
    global.params.argv0 = buf;
#else
    global.params.argv0 = argv[0];
#endif
    global.params.useSwitchError = 1;

    global.params.linkswitches = new Strings();
    global.params.libfiles = new Strings();
    global.params.objfiles = new Strings();
    global.params.ddocfiles = new Strings();

    global.params.moduleDeps = NULL;
    global.params.moduleDepsFile = NULL;

    // Set predefined version identifiers
    VersionCondition::addPredefinedGlobalIdent("LLVM");
    VersionCondition::addPredefinedGlobalIdent("LDC");
    VersionCondition::addPredefinedGlobalIdent("all");
#if DMDV2
    VersionCondition::addPredefinedGlobalIdent("D_Version2");
#endif

    // build complete fixed up list of command line arguments
    std::vector<const char*> final_args;
    final_args.reserve(argc);

    // insert command line args until -run is reached
    int run_argnum = 1;
    while (run_argnum < argc && strncmp(argv[run_argnum], "-run", 4) != 0)
        ++run_argnum;
    final_args.insert(final_args.end(), &argv[0], &argv[run_argnum]);

    // read the configuration file
    ConfigFile cfg_file;

    // just ignore errors for now, they are still printed
#if DMDV2
#define CFG_FILENAME "ldc2.conf"
#else
#define CFG_FILENAME "ldc.conf"
#endif
    cfg_file.read(global.params.argv0, (void*)main, CFG_FILENAME);
#undef CFG_FILENAME

    // insert config file additions to the argument list
    final_args.insert(final_args.end(), cfg_file.switches_begin(), cfg_file.switches_end());

    // insert -run and everything beyond
    final_args.insert(final_args.end(), &argv[run_argnum], &argv[argc]);

#if 0
    for (size_t i = 0; i < final_args.size(); ++i)
    {
        printf("final_args[%zu] = %s\n", i, final_args[i]);
    }
#endif

    // Initialize LLVM.
    // Initialize targets first, so that --version shows registered targets.
    llvm::InitializeAllTargetInfos();
    llvm::InitializeAllTargets();
    llvm::InitializeAllTargetMCs();
    llvm::InitializeAllAsmPrinters();
    llvm::InitializeAllAsmParsers();

    // Handle fixed-up arguments!
    cl::SetVersionPrinter(&printVersion);
    cl::ParseCommandLineOptions(final_args.size(), const_cast<char**>(&final_args[0]), "LLVM-based D Compiler\n", true);

    // Print config file path if -v was passed
    if (global.params.verbose) {
        const std::string& path = cfg_file.path();
        if (!path.empty())
            printf("config    %s\n", path.c_str());
    }

    bool skipModules = mCPU == "help" ||(!mAttrs.empty() && mAttrs.front() == "help");

    // Negated options
    global.params.link = !compileOnly;
    global.params.obj = !dontWriteObj;
    global.params.useInlineAsm = !noAsm;

    // String options: std::string --> char*
    initFromString(global.params.objname, objectFile);
    initFromString(global.params.objdir, objectDir);

    initFromString(global.params.docdir, ddocDir);
    initFromString(global.params.docname, ddocFile);
    global.params.doDocComments |=
        global.params.docdir || global.params.docname;

    initFromString(global.params.xfilename, jsonFile);
    if (global.params.xfilename)
        global.params.doXGeneration = true;

    initFromString(global.params.hdrdir, hdrDir);
    initFromString(global.params.hdrname, hdrFile);
    global.params.doHdrGeneration |=
        global.params.hdrdir || global.params.hdrname;

    initFromString(global.params.moduleDepsFile, moduleDepsFile);
    if (global.params.moduleDepsFile != NULL)
    {
         global.params.moduleDeps = new OutBuffer;
    }

    processVersions(debugArgs, "debug",
        DebugCondition::setGlobalLevel,
        DebugCondition::addGlobalIdent);
    processVersions(versions, "version",
        VersionCondition::setGlobalLevel,
        VersionCondition::addGlobalIdent);

    global.params.output_o =
        (opts::output_o == cl::BOU_UNSET
            && !(opts::output_bc || opts::output_ll || opts::output_s))
        ? OUTPUTFLAGdefault
        : opts::output_o == cl::BOU_TRUE
            ? OUTPUTFLAGset
            : OUTPUTFLAGno;
    global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno;
    global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno;
    global.params.output_s  = opts::output_s  ? OUTPUTFLAGset : OUTPUTFLAGno;

    templateLinkage =
        opts::linkonceTemplates ? LLGlobalValue::LinkOnceODRLinkage
                                : LLGlobalValue::WeakODRLinkage;

    if (global.params.run || !runargs.empty()) {
        // FIXME: how to properly detect the presence of a PositionalEatsArgs
        // option without parameters? We want to emit an error in that case...
        // You'd think getNumOccurrences would do it, but it just returns the
        // number of parameters)
        // NOTE: Hacked around it by detecting -run in getenv_setargv(), where
        // we're looking for it anyway, and pre-setting the flag...
        global.params.run = true;
        if (!runargs.empty()) {
            files.push(mem.strdup(runargs[0].c_str()));
        } else {
            global.params.run = false;
            error("Expected at least one argument to '-run'\n");
        }
    }


    files.reserve(fileList.size());
    typedef std::vector<std::string>::iterator It;
    for(It I = fileList.begin(), E = fileList.end(); I != E; ++I)
        if (!I->empty())
            files.push(mem.strdup(I->c_str()));

    if (global.errors)
    {
        fatal();
    }
    if (files.dim == 0 && !skipModules)
    {
        cl::PrintHelpMessage();
        return EXIT_FAILURE;
    }

#if LDC_LLVM_VER >= 301
    llvm::TargetOptions targetOptions;
#endif

    Array* libs;
    if (global.params.symdebug)
    {
        libs = global.params.debuglibnames;
#if LDC_LLVM_VER == 300
        llvm::NoFramePointerElim = true;
#else
        targetOptions.NoFramePointerElim = true;
#endif
    }
    else
        libs = global.params.defaultlibnames;

    if (!noDefaultLib)
    {
        if (libs)
        {
            for (unsigned i = 0; i < libs->dim; i++)
            {
                char* lib = static_cast<char *>(libs->data[i]);
                char *arg = static_cast<char *>(mem.malloc(strlen(lib) + 3));
                strcpy(arg, "-l");
                strcpy(arg+2, lib);
                global.params.linkswitches->push(arg);
            }
        }
        else
        {
#if DMDV2
            global.params.linkswitches->push(mem.strdup("-ldruntime-ldc"));
#else
            global.params.linkswitches->push(mem.strdup("-lldc-runtime"));
            global.params.linkswitches->push(mem.strdup("-ltango-cc-tango"));
            global.params.linkswitches->push(mem.strdup("-ltango-gc-basic"));
            // pass the runtime again to resolve issues
            // with linking order
            global.params.linkswitches->push(mem.strdup("-lldc-runtime"));
#endif
        }
    }

    if (global.params.run)
        quiet = 1;

    if (global.params.useUnitTests)
        global.params.useAssert = 1;

    // LDC output determination

    // if we don't link, autodetect target from extension
    if(!global.params.link && global.params.objname) {
        ext = FileName::ext(global.params.objname);
        bool autofound = false;
        if (!ext) {
            // keep things as they are
        } else if (strcmp(ext, global.ll_ext) == 0) {
            global.params.output_ll = OUTPUTFLAGset;
            autofound = true;
        } else if (strcmp(ext, global.bc_ext) == 0) {
            global.params.output_bc = OUTPUTFLAGset;
            autofound = true;
        } else if (strcmp(ext, global.s_ext) == 0) {
            global.params.output_s = OUTPUTFLAGset;
            autofound = true;
        } else if (strcmp(ext, global.obj_ext) == 0) {
            global.params.output_o = OUTPUTFLAGset;
            autofound = true;
        } else {
            // append dot, so forceExt won't change existing name even if it contains dots
            size_t len = strlen(global.params.objname);
            size_t extlen = strlen(".");
            char* s = static_cast<char *>(mem.malloc(len + 1 + extlen + 1));
            memcpy(s, global.params.objname, len);
            s[len] = '.';
            s[len+1+extlen] = 0;
            global.params.objname = s;

        }
        if(autofound && global.params.output_o == OUTPUTFLAGdefault)
            global.params.output_o = OUTPUTFLAGno;
    }

    // only link if possible
    if (!global.params.obj || !global.params.output_o || createStaticLib)
        global.params.link = 0;

    if (createStaticLib && createSharedLib)
        error("-lib and -shared switches cannot be used together");

    if (createSharedLib && mRelocModel == llvm::Reloc::Default)
        mRelocModel = llvm::Reloc::PIC_;

    if (global.params.link && !createSharedLib)
    {
        global.params.exefile = global.params.objname;
        if (files.dim > 1)
            global.params.objname = NULL;
    }
    else if (global.params.run)
    {
        error("flags conflict with -run");
        fatal();
    }
    else if (global.params.objname && files.dim > 1) {
        if (createStaticLib || createSharedLib)
        {
            singleObj = true;
        }
        if (!singleObj)
        {
            error("multiple source files, but only one .obj name");
            fatal();
        }
    }

    if (soname.getNumOccurrences() > 0 && !createSharedLib) {
        error("-soname can be used only when building a shared library");
        fatal();
    }

    // create a proper target
    Ir ir;

    // check -m32/64 sanity
    if (m32bits && m64bits)
        error("cannot use both -m32 and -m64 options");
    else if ((m32bits || m64bits) && (!mArch.empty() || !mTargetTriple.empty()))
        error("-m32 and -m64 switches cannot be used together with -march and -mtriple switches");
    if (global.errors)
        fatal();

    // override triple if needed
    std::string defaultTriple = llvm::sys::getDefaultTargetTriple();
    if (sizeof(void*) == 4 && m64bits)
    {
#if LDC_LLVM_VER >= 301
        defaultTriple = llvm::Triple(defaultTriple).get64BitArchVariant().str();
#else
        defaultTriple = llvm::Triple__get64BitArchVariant(defaultTriple).str();
#endif
    }
    else if (sizeof(void*) == 8 && m32bits)
    {
#if LDC_LLVM_VER >= 301
        defaultTriple = llvm::Triple(defaultTriple).get32BitArchVariant().str();
#else
        defaultTriple = llvm::Triple__get32BitArchVariant(defaultTriple).str();
#endif
    }

    // did the user override the target triple?
    if (mTargetTriple.empty())
    {
        if (!mArch.empty())
        {
            error("you must specify a target triple as well with -mtriple when using the -march option");
            fatal();
        }
        global.params.targetTriple = defaultTriple.c_str();
    }
    else
    {
        global.params.targetTriple = llvm::Triple::normalize(mTargetTriple).c_str();
    }

    std::string triple = global.params.targetTriple;

    // Allocate target machine.
    const llvm::Target *theTarget = NULL;
    // Check whether the user has explicitly specified an architecture to compile for.
    if (mArch.empty())
    {
        std::string Err;
        theTarget = llvm::TargetRegistry::lookupTarget(triple, Err);
        if (theTarget == 0)
        {
            error("%s Please use the -march option.", Err.c_str());
            fatal();
        }
    }
    else
    {
        for (llvm::TargetRegistry::iterator it = llvm::TargetRegistry::begin(),
             ie = llvm::TargetRegistry::end(); it != ie; ++it)
        {
            if (mArch == it->getName())
            {
                theTarget = &*it;
                break;
            }
        }

        if (!theTarget)
        {
            error("invalid target '%s'", mArch.c_str());
            fatal();
        }
    }

    // Package up features to be passed to target/subtarget
    std::string FeaturesStr;
    if (mCPU.size() || mAttrs.size())
    {
        llvm::SubtargetFeatures Features;
        for (unsigned i = 0; i != mAttrs.size(); ++i)
            Features.AddFeature(mAttrs[i]);
        FeaturesStr = Features.getString();
    }

    // FIXME
    //std::auto_ptr<llvm::TargetMachine> target(theTarget->createTargetMachine(triple, FeaturesStr));
    //assert(target.get() && "Could not allocate target machine!");
    //gTargetMachine = target.get();

#if LDC_LLVM_VER == 300
    llvm::TargetMachine* target = theTarget->createTargetMachine(triple, mCPU, FeaturesStr,
                                                                 mRelocModel, mCodeModel);
#else
    llvm::TargetMachine * target = theTarget->createTargetMachine(
        llvm::StringRef(triple),
        llvm::StringRef(mCPU),
        llvm::StringRef(FeaturesStr),
        targetOptions,
        mRelocModel,
        mCodeModel,
        codeGenOptLevel()
    );
#endif

    gTargetMachine = target;

    gTargetData = target->getTargetData();

    // get final data layout
    std::string datalayout = gTargetData->getStringRepresentation();
    global.params.dataLayout = datalayout.c_str();

    global.params.llvmArch = theTarget->getName();

    if (strcmp(global.params.llvmArch,"x86")==0) {
        VersionCondition::addPredefinedGlobalIdent("X86");
        global.params.isLE = true;
        global.params.is64bit = false;
        global.params.cpu = ARCHx86;
        if (global.params.useInlineAsm) {
            VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86");
        }
    }
    else if (strcmp(global.params.llvmArch,"x86-64")==0) {
        VersionCondition::addPredefinedGlobalIdent("X86_64");
        global.params.isLE = true;
        global.params.is64bit = true;
        global.params.cpu = ARCHx86_64;
        if (global.params.useInlineAsm) {
            VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64");
        }
    }
    else if (strcmp(global.params.llvmArch,"ppc32")==0) {
        VersionCondition::addPredefinedGlobalIdent("PPC");
        global.params.isLE = false;
        global.params.is64bit = false;
        global.params.cpu = ARCHppc;
    }
    else if (strcmp(global.params.llvmArch,"ppc64")==0) {
        VersionCondition::addPredefinedGlobalIdent("PPC64");
        global.params.isLE = false;
        global.params.is64bit = true;
        global.params.cpu = ARCHppc_64;
    }
    else if (strcmp(global.params.llvmArch,"arm")==0) {
        VersionCondition::addPredefinedGlobalIdent("ARM");
        global.params.isLE = true;
        global.params.is64bit = false;
        global.params.cpu = ARCHarm;
    }
    else if (strcmp(global.params.llvmArch,"thumb")==0) {
        VersionCondition::addPredefinedGlobalIdent("ARM");
        VersionCondition::addPredefinedGlobalIdent("Thumb");
        global.params.isLE = true;
        global.params.is64bit = false;
        global.params.cpu = ARCHthumb;
    }
    else {
        error("invalid cpu architecture specified: %s", global.params.llvmArch);
        fatal();
    }

    // endianness
    if (global.params.isLE) {
        VersionCondition::addPredefinedGlobalIdent("LittleEndian");
    }
    else {
        VersionCondition::addPredefinedGlobalIdent("BigEndian");
    }

    // a generic 64bit version
    if (global.params.is64bit) {
        VersionCondition::addPredefinedGlobalIdent("LLVM64");
        // FIXME: is this always correct?
        VersionCondition::addPredefinedGlobalIdent("D_LP64");
    }

    if (mRelocModel == llvm::Reloc::PIC_) {
        VersionCondition::addPredefinedGlobalIdent("D_PIC");
    }

    // parse the OS out of the target triple
    // see http://gcc.gnu.org/install/specific.html for details
    // also llvm's different SubTargets have useful information
    switch (llvm::Triple(triple).getOS())
    {
        case llvm::Triple::Win32:
            global.params.os = OSWindows;
            VersionCondition::addPredefinedGlobalIdent("Windows");
            VersionCondition::addPredefinedGlobalIdent("Win32");
            if (global.params.is64bit) {
                VersionCondition::addPredefinedGlobalIdent("Win64");
            }
            break;
        case llvm::Triple::MinGW32:
            global.params.os = OSWindows;
            VersionCondition::addPredefinedGlobalIdent("Windows");
            VersionCondition::addPredefinedGlobalIdent("Win32");
            VersionCondition::addPredefinedGlobalIdent("mingw32");
            VersionCondition::addPredefinedGlobalIdent("MinGW");
            if (global.params.is64bit) {
                VersionCondition::addPredefinedGlobalIdent("Win64");
            }
            break;
        case llvm::Triple::Cygwin:
            error("CygWin is not yet supported");
            fatal();
            break;
        case llvm::Triple::Linux:
            global.params.os = OSLinux;
            VersionCondition::addPredefinedGlobalIdent("linux");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::Haiku:
            global.params.os = OSHaiku;
            VersionCondition::addPredefinedGlobalIdent("Haiku");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::Darwin:
            global.params.os = OSMacOSX;
            VersionCondition::addPredefinedGlobalIdent("OSX");
            VersionCondition::addPredefinedGlobalIdent("darwin");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::FreeBSD:
            global.params.os = OSFreeBSD;
            VersionCondition::addPredefinedGlobalIdent("freebsd");
            VersionCondition::addPredefinedGlobalIdent("FreeBSD");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        case llvm::Triple::Solaris:
            global.params.os = OSSolaris;
            VersionCondition::addPredefinedGlobalIdent("solaris");
            VersionCondition::addPredefinedGlobalIdent("Solaris");
            VersionCondition::addPredefinedGlobalIdent("Posix");
            break;
        default:
            error("target '%s' is not yet supported", global.params.targetTriple);
            fatal();
    }

    // Expose LLVM version to runtime
#define STR(x) #x
#define XSTR(x) STR(x)
    VersionCondition::addPredefinedGlobalIdent("LDC_LLVM_"XSTR(LDC_LLVM_VER));
#undef XSTR
#undef STR

    if (global.params.os == OSWindows) {
        global.dll_ext = "dll";
        global.lib_ext = "lib";
    } else {
        global.dll_ext = "so";
        global.lib_ext = "a";
    }

    // added in 1.039
    if (global.params.doDocComments)
        VersionCondition::addPredefinedGlobalIdent("D_Ddoc");

#if DMDV2
    // unittests?
    if (global.params.useUnitTests)
        VersionCondition::addPredefinedGlobalIdent("unittest");
#endif

    // Initialization
    Type::init(&ir);
    Id::initialize();
    Module::init();
    initPrecedence();

    backend_init();

    //printf("%d source files\n",files.dim);

    // Build import search path
    if (global.params.imppath)
    {
        for (unsigned i = 0; i < global.params.imppath->dim; i++)
        {
            char *path = static_cast<char *>(global.params.imppath->data[i]);
            Strings *a = FileName::splitPath(path);

            if (a)
            {
                if (!global.path)
                    global.path = new Strings();
                global.path->append(a);
            }
        }
    }

    // Build string import search path
    if (global.params.fileImppath)
    {
        for (unsigned i = 0; i < global.params.fileImppath->dim; i++)
        {
            char *path = static_cast<char *>(global.params.fileImppath->data[i]);
            Strings *a = FileName::splitPath(path);

            if (a)
            {
                if (!global.filePath)
                    global.filePath = new Strings();
                global.filePath->append(a);
            }
        }
    }

    // Create Modules
    Modules modules;
    modules.reserve(files.dim);
    for (unsigned i = 0; i < files.dim; i++)
    {   Identifier *id;
        char *ext;
        char *name;

        p = static_cast<char *>(files.data[i]);

        p = FileName::name(p);      // strip path
        ext = FileName::ext(p);
        if (ext)
        {
#if POSIX
            if (strcmp(ext, global.obj_ext) == 0 ||
            strcmp(ext, global.bc_ext) == 0)
#else
            if (stricmp(ext, global.obj_ext) == 0 ||
            stricmp(ext, global.bc_ext) == 0)
#endif
            {
                global.params.objfiles->push(static_cast<char *>(files.data[i]));
                continue;
            }

#if POSIX
            if (strcmp(ext, "a") == 0)
#elif __MINGW32__
            if (stricmp(ext, "a") == 0)
#else
            if (stricmp(ext, "lib") == 0)
#endif
            {
                global.params.libfiles->push(static_cast<char *>(files.data[i]));
                continue;
            }

            if (strcmp(ext, global.ddoc_ext) == 0)
            {
                global.params.ddocfiles->push(static_cast<char *>(files.data[i]));
                continue;
            }

            if (FileName::equals(ext, global.json_ext))
            {
                global.params.doXGeneration = 1;
                global.params.xfilename = static_cast<char *>(files.data[i]);
                continue;
            }

#if !POSIX
            if (stricmp(ext, "res") == 0)
            {
                global.params.resfile = static_cast<char *>(files.data[i]);
                continue;
            }

            if (stricmp(ext, "def") == 0)
            {
                global.params.deffile = static_cast<char *>(files.data[i]);
                continue;
            }

            if (stricmp(ext, "exe") == 0)
            {
                global.params.exefile = static_cast<char *>(files.data[i]);
                continue;
            }
#endif

            if (stricmp(ext, global.mars_ext) == 0 ||
            stricmp(ext, global.hdr_ext) == 0 ||
            stricmp(ext, "htm") == 0 ||
            stricmp(ext, "html") == 0 ||
            stricmp(ext, "xhtml") == 0)
            {
                ext--;          // skip onto '.'
                assert(*ext == '.');
                name = static_cast<char *>(mem.malloc((ext - p) + 1));
                memcpy(name, p, ext - p);
                name[ext - p] = 0;      // strip extension

                if (name[0] == 0 ||
                    strcmp(name, "..") == 0 ||
                    strcmp(name, ".") == 0)
                {
            Linvalid:
                    error("invalid file name '%s'", static_cast<char *>(files.data[i]));
                    fatal();
                }
            }
            else
            {   error("unrecognized file extension %s\n", ext);
                fatal();
            }
        }
        else
        {   name = p;
            if (!*name)
            goto Linvalid;
        }

        id = Lexer::idPool(name);
        m = new Module(static_cast<char *>(files.data[i]), id, global.params.doDocComments, global.params.doHdrGeneration);
        m->isRoot = true;
        modules.push(m);
    }

    // Read files, parse them
    for (unsigned i = 0; i < modules.dim; i++)
    {
        m = static_cast<Module *>(modules.data[i]);
        if (global.params.verbose)
            printf("parse     %s\n", m->toChars());
        if (!Module::rootModule)
            Module::rootModule = m;
        m->importedFrom = m;
        m->read(0);
        m->parse(global.params.doDocComments);
        m->buildTargetFiles(singleObj);
        m->deleteObjFile();
        if (m->isDocFile)
        {
            m->gendocfile();

            // Remove m from list of modules
            modules.remove(i);
            i--;
        }
    }
    if (global.errors)
        fatal();

    if (global.params.doHdrGeneration)
    {
        /* Generate 'header' import files.
         * Since 'header' import files must be independent of command
         * line switches and what else is imported, they are generated
         * before any semantic analysis.
         */
        for (unsigned i = 0; i < modules.dim; i++)
        {
            m = static_cast<Module *>(modules.data[i]);
            if (global.params.verbose)
                printf("import    %s\n", m->toChars());
            m->genhdrfile();
        }
    }
    if (global.errors)
        fatal();

    // load all unconditional imports for better symbol resolving
    for (unsigned i = 0; i < modules.dim; i++)
    {
       m = static_cast<Module *>(modules.data[i]);
       if (global.params.verbose)
           printf("importall %s\n", m->toChars());
       m->importAll(0);
    }
    if (global.errors)
       fatal();

    // Do semantic analysis
    for (unsigned i = 0; i < modules.dim; i++)
    {
        m = static_cast<Module *>(modules.data[i]);
        if (global.params.verbose)
            printf("semantic  %s\n", m->toChars());
        m->semantic();
    }
    if (global.errors)
        fatal();

    Module::dprogress = 1;
    Module::runDeferredSemantic();

    // Do pass 2 semantic analysis
    for (unsigned i = 0; i < modules.dim; i++)
    {
        m = static_cast<Module *>(modules.data[i]);
        if (global.params.verbose)
            printf("semantic2 %s\n", m->toChars());
        m->semantic2();
    }
    if (global.errors)
        fatal();

    // Do pass 3 semantic analysis
    for (unsigned i = 0; i < modules.dim; i++)
    {
        m = static_cast<Module *>(modules.data[i]);
        if (global.params.verbose)
            printf("semantic3 %s\n", m->toChars());
        m->semantic3();
    }
    if (global.errors)
        fatal();

#if !IN_LLVM
    // Scan for functions to inline
    if (global.params.useInline)
    {
        /* The problem with useArrayBounds and useAssert is that the
         * module being linked to may not have generated them, so if
         * we inline functions from those modules, the symbols for them will
         * not be found at link time.
         */
        if (!global.params.useArrayBounds && !global.params.useAssert)
#else
    // This doesn't play nice with debug info at the moment
    if (!global.params.symdebug && willInline())
    {
        global.params.useAvailableExternally = true;
        Logger::println("Running some extra semantic3's for inlining purposes");
#endif
        {
            // Do pass 3 semantic analysis on all imported modules,
            // since otherwise functions in them cannot be inlined
            for (unsigned i = 0; i < Module::amodules.dim; i++)
            {
                m = static_cast<Module *>(Module::amodules.data[i]);
                if (global.params.verbose)
                    printf("semantic3 %s\n", m->toChars());
                m->semantic2();
                m->semantic3();
            }
            if (global.errors)
                fatal();
        }

#if !IN_LLVM
        for (int i = 0; i < modules.dim; i++)
        {
            m = static_cast<Module *>(modules.data[i]);
            if (global.params.verbose)
                printf("inline scan %s\n", m->toChars());
            m->inlineScan();
        }
#endif
    }
    if (global.errors || global.warnings)
        fatal();

    // write module dependencies to file if requested
    if (global.params.moduleDepsFile != NULL)
    {
        assert (global.params.moduleDepsFile != NULL);

        File deps(global.params.moduleDepsFile);
        OutBuffer* ob = global.params.moduleDeps;
        deps.setbuffer(static_cast<void*>(ob->data), ob->offset);
        deps.write();
    }

    // collects llvm modules to be linked if singleobj is passed
    std::vector<llvm::Module*> llvmModules;
    llvm::LLVMContext& context = llvm::getGlobalContext();

    // Generate output files
    for (unsigned i = 0; i < modules.dim; i++)
    {
        m = static_cast<Module *>(modules.data[i]);
        if (global.params.verbose)
            printf("code      %s\n", m->toChars());
        if (global.params.obj)
        {
            llvm::Module* lm = m->genLLVMModule(context, &ir);
            if (!singleObj)
            {
                m->deleteObjFile();
                writeModule(lm, m->objfile->name->str);
                global.params.objfiles->push(m->objfile->name->str);
                delete lm;
            }
            else
                llvmModules.push_back(lm);
        }
        if (global.errors)
            m->deleteObjFile();
        else
        {
            if (global.params.doDocComments)
            m->gendocfile();
        }
    }

    // internal linking for singleobj
    if (singleObj && llvmModules.size() > 0)
    {
        Module* m = static_cast<Module*>(modules.data[0]);
        char* name = m->toChars();
        char* filename = m->objfile->name->str;

        llvm::Linker linker(name, name, context);

        std::string errormsg;
        for (int i = 0; i < llvmModules.size(); i++)
        {
            if(linker.LinkInModule(llvmModules[i], &errormsg))
                error("%s", errormsg.c_str());
            delete llvmModules[i];
        }

        m->deleteObjFile();
        writeModule(linker.getModule(), filename);
        global.params.objfiles->push(filename);
    }

    // output json file
    if (global.params.doXGeneration)
        json_generate(&modules);

    backend_term();
    if (global.errors)
        fatal();

    if (!global.params.objfiles->dim)
    {
        if (global.params.link)
            error("no object files to link");
        else if (createStaticLib)
            error("no object files");
    }
    else
    {
        if (global.params.link)
            status = linkObjToBinary(createSharedLib);
        else if (createStaticLib)
            createStaticLibrary();

        if (global.params.run)
        {
            if (!status)
            {
                status = runExecutable();

                /* Delete .obj files and .exe file
                 */
                for (unsigned i = 0; i < modules.dim; i++)
                {
                    m = static_cast<Module *>(modules.data[i]);
                    m->deleteObjFile();
                }
                deleteExecutable();
            }
        }
    }

    return status;
}