view main.d @ 178:e3afd1303184

Many small bugs fixed Made all classes derive from TObject to detect memory leaks (functionality is disabled for now) Began work on overriding backend memory allocations (to avoid memory leaks)
author korDen
date Sun, 17 Oct 2010 07:42:00 +0400
parents 96c0fff6897d
children cd48cb899aee
line wrap: on
line source

module main;

import dmd.Macro;
import dmd.Array;
import dmd.Module;
import dmd.Global;
import dmd.VersionCondition;
import dmd.DebugCondition;
import dmd.Loc;
import dmd.Lexer;
import dmd.OutBuffer;
import dmd.FileName;
import dmd.Type;
import dmd.File;
import dmd.Id;
import dmd.Identifier;
import dmd.Json;
import dmd.Library;
import dmd.TOK;
import dmd.String;
import dmd.backend.glue;

import std.stdarg;
import std.string : toStringz;
import std.exception;

import core.stdc.string;
import core.stdc.stdio;
import core.stdc.ctype;
import core.stdc.errno;
import core.stdc.stdlib;
import core.stdc.limits;

import core.memory;

import dbg.CallStackInfo;

import dmd.Util;

enum ExitCode
{
	EXIT_SUCCESS = 0,
}

version = CrashHandler;

version (CrashHandler) {
version(Linux)
{
extern (C) extern __gshared bool rt_trapExceptions;

static this() {
	rt_trapExceptions = false;
}

}


version(Windows)
{

version (Windows)
{
    private import core.stdc.wchar_;

    extern (Windows) alias int function() FARPROC;
    extern (Windows) FARPROC    GetProcAddress(void*, in char*);
    extern (Windows) void*      LoadLibraryA(in char*);
    extern (Windows) int        FreeLibrary(void*);
    extern (Windows) void*      LocalFree(void*);
    extern (Windows) wchar_t*   GetCommandLineW();
    extern (Windows) wchar_t**  CommandLineToArgvW(wchar_t*, int*);
    extern (Windows) export int WideCharToMultiByte(uint, uint, wchar_t*, int, char*, int, char*, int);
    pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW
}

shared bool _d_isHalting = false;
__gshared string[] _d_args = null;

version(Posix)
{
    extern (C) void _STI_monitor_staticctor();
    extern (C) void _STD_monitor_staticdtor();
    extern (C) void _STI_critical_init();
    extern (C) void _STD_critical_term();
}

extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void _minit();
extern (C) void _moduleCtor();
extern (C) void _moduleDtor();
extern (C) bool runModuleUnitTests();
extern (C) void thread_joinAll();

import rt.memory;

extern (C) int main(int argc, char** argv)
{
    char[][] args;
    int result;

    version (OSX)
    {   /* OSX does not provide a way to get at the top of the
         * stack, except for the magic value 0xC0000000.
         * But as far as the gc is concerned, argv is at the top
         * of the main thread's stack, so save the address of that.
         */
        __osx_stack_end = cast(void*)&argv;
    }

    version (FreeBSD) version (D_InlineAsm_X86)
    {
        /*
         * FreeBSD/i386 sets the FPU precision mode to 53 bit double.
         * Make it 64 bit extended.
         */
        ushort fpucw;
        asm
        {
            fstsw   fpucw;
            or      fpucw, 0b11_00_111111; // 11: use 64 bit extended-precision
                                           // 111111: mask all FP exceptions
            fldcw   fpucw;
        }
    }

    version (Posix)
    {
        _STI_monitor_staticctor();
        _STI_critical_init();
    }

    version (Windows)
    {
        wchar_t*  wcbuf = GetCommandLineW();
        size_t    wclen = wcslen(wcbuf);
        int       wargc = 0;
        wchar_t** wargs = CommandLineToArgvW(wcbuf, &wargc);
        assert(wargc == argc);

        char*     cargp = null;
        size_t    cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, 0);

        cargp = cast(char*) alloca(cargl);
        args  = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc];

        for (size_t i = 0, p = 0; i < wargc; i++)
        {
            int wlen = wcslen(wargs[i]);
            int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, 0);
            args[i]  = cargp[p .. p+clen];
            p += clen; assert(p <= cargl);
            WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, 0);
        }
        LocalFree(wargs);
        wargs = null;
        wargc = 0;
    }
    else version (Posix)
    {
        char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof);
        scope(exit) free(am);

        for (size_t i = 0; i < argc; i++)
        {
            auto len = strlen(argv[i]);
            am[i] = argv[i][0 .. len];
        }
        args = am[0 .. argc];
    }
    _d_args = cast(string[]) args;
	
	void runMain()
    {
		CrashHandlerInit();
		//	while (true)
		{
			result = main(_d_args);
		}
    }

    void runAll()
    {
        gc_init();
        initStaticDataGC();
        version (Windows)
            _minit();
        _moduleCtor();
        _moduleTlsCtor();
        if (runModuleUnitTests())
            runMain();
        else
            result = EXIT_FAILURE;
        _moduleTlsDtor();
        thread_joinAll();
        _d_isHalting = true;
        _moduleDtor();
        gc_term();
    }

    runAll();

    version (Posix)
    {
        _STD_critical_term();
        _STD_monitor_staticdtor();
    }
    return result;
}

}
}

int main(string[] args)
{
	GC.disable();
	
    Array files = new Array();
    Array libmodules = new Array();
    Module m;
    int status = ExitCode.EXIT_SUCCESS;
    int argcstart = args.length;
    int setdebuglib = 0;
    byte noboundscheck = 0;
	
	global = new Global();

///    if (response_expand(&argc,&argv))        // expand response files
///        error("can't open response file");

    files.reserve(args.length - 1);

    // Set default values
    global.params.argv0 = args[0];
    global.params.link = 1;
    global.params.useAssert = 1;
    global.params.useInvariants = 1;
    global.params.useIn = 1;
    global.params.useOut = 1;
    global.params.useArrayBounds = 2;	// default to all functions
    global.params.useSwitchError = 1;
    global.params.useInline = 0;
    global.params.obj = 1;
    global.params.Dversion = 2;
    global.params.quiet = 1;

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

version (TARGET_WINDOS) {
    global.params.defaultlibname = "phobos";
} else version (POSIX) { //#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
    global.params.defaultlibname = "phobos2";
} else version (TARGET_NET) {
} else {
    static assert(false, "fix this");
}

    // Predefine version identifiers
    VersionCondition.addPredefinedGlobalIdent("DigitalMars");

version (TARGET_WINDOS) {
    VersionCondition.addPredefinedGlobalIdent("Windows");
    global.params.isWindows = 1;
version (TARGET_NET) {
    // TARGET_NET macro is NOT mutually-exclusive with TARGET_WINDOS
    VersionCondition.addPredefinedGlobalIdent("D_NET");
}
} else version (TARGET_LINUX) {
    VersionCondition.addPredefinedGlobalIdent("Posix");
    VersionCondition.addPredefinedGlobalIdent("linux");
    global.params.isLinux = 1;
} else version (TARGET_OSX) {
    VersionCondition.addPredefinedGlobalIdent("Posix");
    VersionCondition.addPredefinedGlobalIdent("OSX");
    global.params.isOSX = 1;

    // For legacy compatibility
    VersionCondition.addPredefinedGlobalIdent("darwin");
} else version (TARGET_FREEBSD) {
    VersionCondition.addPredefinedGlobalIdent("Posix");
    VersionCondition.addPredefinedGlobalIdent("FreeBSD");
    global.params.isFreeBSD = 1;
} else version (TARGET_SOLARIS) {
    VersionCondition.addPredefinedGlobalIdent("Posix");
    VersionCondition.addPredefinedGlobalIdent("Solaris");
    global.params.isSolaris = 1;
} else {
        static assert (false, "fix this");
}

    VersionCondition.addPredefinedGlobalIdent("LittleEndian");
    //VersionCondition.addPredefinedGlobalIdent("D_Bits");
version (DMDV2) {
    VersionCondition.addPredefinedGlobalIdent("D_Version2");
}
    VersionCondition.addPredefinedGlobalIdent("all");

version (Windows)
{
	inifile(args[0], "sc.ini");
}
 else version (Posix) ///linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4
{
	inifile(args[0], "dmd.conf");
}
else
{
	static assert (false, "fix this");
}
    args = getenv_setargv("DFLAGS", args);

version (disabled) {
    for (i = 0; i < argc; i++)
    {
        writef("argv[%d] = '%s'\n", i, argv[i]);
    }
}

    foreach(i; 1..args.length)
    {
		auto arg = args[i];
        auto p = arg.ptr;
        if (*p == '-')
        {
			arg = arg[1..$];
            if (arg == "d")
                global.params.useDeprecated = 1;
            else if (arg == "c")
                global.params.link = 0;
            else if (arg == "cov")
                global.params.cov = 1;
///version (XXX) {// TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
///            else if (arg == "fPIC")
///                global.params.pic = 1;
///}
            else if (arg == "multiobj")
                global.params.multiobj = 1;
            else if (arg == "g")
                global.params.symdebug = 1;
            else if (arg == "gc")
                global.params.symdebug = 2;
            else if (arg == "gt")
            {        error("use -profile instead of -gt\n");
                global.params.trace = 1;
            }
            else if (arg == "m64")
                global.params.isX86_64 = 1;
            else if (arg == "profile")
                global.params.trace = 1;
            else if (arg == "v")
                global.params.verbose = 1;
///version (DMDV2) {
            else if (arg == "vtls")
                global.params.vtls = 1;
///}
            else if (arg == "v1")
            {
version (DMDV1) {
                global.params.Dversion = 1;
} else {
                error("use DMD 1.0 series compilers for -v1 switch");
                break;
}
            }
            else if (arg == "w")
                global.params.warnings = 1;
            else if (arg == "O")
                global.params.optimize = 1;
            else if (p[1] == 'o')
            {
                switch (p[2])
                {
                    case '-':
                        global.params.obj = 0;
                        break;

                    case 'd':
                        if (!p[3])
                            goto Lnoarg;
                        global.params.objdir = arg[(p - arg.ptr) + 3..$];
                        break;

                    case 'f':
					{
                        if (!p[3])
                            goto Lnoarg;
							
                        global.params.objname = arg[(p - arg.ptr) + 3..$];
                        break;
					}

                    case 'p':
                        if (p[3])
                            goto Lerror;
                        global.params.preservePaths = 1;
                        break;

                    case 0:
                        error("-o no longer supported, use -of or -od");
                        break;

                    default:
                        goto Lerror;
                }
            }
            else if (p[1] == 'D')
            {        global.params.doDocComments = 1;
                switch (p[2])
                {
                    case 'd':
                        if (!p[3])
                            goto Lnoarg;
                        global.params.docdir = arg[(p - arg.ptr) + 3..$];
                        break;
                    case 'f':
                        if (!p[3])
                            goto Lnoarg;
                        global.params.docname = arg[(p - arg.ptr) + 3..$];
                        break;

                    case 0:
                        break;

                    default:
                        goto Lerror;
                }
            }
///version (_DH) {
            else if (p[1] == 'H')
            {        global.params.doHdrGeneration = 1;
                switch (p[2])
                {
                    case 'd':
                        if (!p[3])
                            goto Lnoarg;
                        global.params.hdrdir = arg[(p - arg.ptr) + 3..$];
                        break;

                    case 'f':
                        if (!p[3])
                            goto Lnoarg;
                        global.params.hdrname = arg[(p - arg.ptr) + 3..$];
                        break;

                    case 0:
                        break;

                    default:
                        goto Lerror;
                }
            }
///}
			else if (p[1] == 'X')
			{
				global.params.doXGeneration = 1;
				switch (p[2])
				{
					case 'f':
					if (!p[3])
						goto Lnoarg;
					global.params.xfilename = arg[(p - arg.ptr) + 3..$];
					break;
	
					case 0:
					break;
	
					default:
					goto Lerror;
				}
			}

            else if (arg == "ignore")
                global.params.ignoreUnsupportedPragmas = 1;
            else if (arg == "inline")
                global.params.useInline = 1;
            else if (arg == "lib")
                global.params.lib = 1;
            else if (arg == "nofloat")
                global.params.nofloat = 1;
            else if (arg == "quiet")
                global.params.quiet = 1;
            else if (arg == "release")
                global.params.release = 1;
///version (DMDV2) {
	        else if (arg == "noboundscheck")
		        noboundscheck = 1;
///}
            else if (arg == "unittest")
                global.params.useUnitTests = 1;
            else if (p[1] == 'I')
            {
                global.params.imppath.push(cast(void*)new String(arg[(p - arg.ptr) + 2..$]));	///
            }
            else if (p[1] == 'J')
            {
                if (!global.params.fileImppath)
                    global.params.fileImppath = new Array();
                global.params.fileImppath.push(cast(void*)new String(arg[(p - arg.ptr) + 2..$]));
            }
            else if (memcmp(p + 1, "debug".ptr, 5) == 0 && p[6] != 'l')
            {
                // Parse:
                //        -debug
                //        -debug=number
                //        -debug=identifier
                if (p[6] == '=')
                {
                    if (isdigit(p[7]))
                    {        long level;

                        errno = 0;
                        level = strtol(p + 7, cast(char**)&p, 10);
                        if (*p || errno || level > INT_MAX)
                            goto Lerror;
                        DebugCondition.setGlobalLevel(cast(int)level);
                    }
                    else if (Lexer.isValidIdentifier(arg[(p - arg.ptr) + 7..$]))		///
                        DebugCondition.addGlobalIdent(p + 7);
                    else
                        goto Lerror;
                }
                else if (p[6])
                    goto Lerror;
                else
                    global.params.debuglevel = 1;
            }
            else if (memcmp(p + 1, "version".ptr, 5) == 0)
            {
                // Parse:
                //        -version=number
                //        -version=identifier
                if (p[8] == '=')
                {
                    if (isdigit(p[9]))
                    {        long level;

                        errno = 0;
                        level = strtol(p + 9, cast(char**)&p, 10);	///
                        if (*p || errno || level > INT_MAX)
                            goto Lerror;
                        VersionCondition.setGlobalLevel(cast(int)level);
                    }
                    else if (Lexer.isValidIdentifier(arg[(p - arg.ptr) + 9..$]))	///
                        VersionCondition.addGlobalIdent(arg[(p - arg.ptr) + 9..$]);
                    else
                        goto Lerror;
                }
                else
                    goto Lerror;
            }
            else if (arg == "-b")
                global.params.debugb = 1;
            else if (arg == "-c")
                global.params.debugc = 1;
            else if (arg == "-f")
                global.params.debugf = 1;
            else if (arg == "-help")
            {        usage();
                exit(EXIT_SUCCESS);
            }
            else if (arg == "-r")
                global.params.debugr = 1;
            else if (arg == "-x")
                global.params.debugx = 1;
            else if (arg == "-y")
                global.params.debugy = 1;
            else if (p[1] == 'L')
            {
                global.params.linkswitches.push(cast(void*)p + 2);
            }
            else if (memcmp(p + 1, "defaultlib=".ptr, 11) == 0)
            {
                global.params.defaultlibname = p + 1 + 11;
            }
            else if (memcmp(p + 1, "debuglib=".ptr, 9) == 0)
            {
                setdebuglib = 1;
                global.params.debuglibname = p + 1 + 9;
            }
            else if (memcmp(p + 1, "deps=".ptr, 5) == 0)
            {
                global.params.moduleDepsFile = arg[(p - arg.ptr) + 1 + 5..$];
                if (!global.params.moduleDepsFile[0])
                    goto Lnoarg;
                global.params.moduleDeps = new OutBuffer;
            }
            else if (memcmp(p + 1, "man".ptr, 3) == 0)
            {
version (Windows) {
version (DMDV1) {
                browse("http://www.digitalmars.com/d/1.0/dmd-windows.html");
} else {
                browse("http://www.digitalmars.com/d/2.0/dmd-windows.html");
}
}
version (linux) {
version (DMDV1) {
                browse("http://www.digitalmars.com/d/1.0/dmd-linux.html");
} else {
                browse("http://www.digitalmars.com/d/2.0/dmd-linux.html");
}
}
version (__APPLE__) {
version (DMDV1) {
                browse("http://www.digitalmars.com/d/1.0/dmd-osx.html");
} else {
                browse("http://www.digitalmars.com/d/2.0/dmd-osx.html");
}
}
version (__FreeBSD__) {
version (DMDV1) {
                browse("http://www.digitalmars.com/d/1.0/dmd-freebsd.html");
} else {
                browse("http://www.digitalmars.com/d/2.0/dmd-freebsd.html");
}
}
                exit(EXIT_SUCCESS);
            }
            else if (arg == "run")
            {        global.params.run = 1;
                global.params.runargs_length = ((i >= argcstart) ? args.length : argcstart) - i - 1;
                if (global.params.runargs_length)
                {
                    files.push(cast(void*)args[i + 1].ptr);
                    global.params.runargs = args[i + 2..$];
                    i += global.params.runargs_length;
                    global.params.runargs_length--;
                }
                else
                {   global.params.run = 0;
                    goto Lnoarg;
                }
            }
            else
            {
             Lerror:
                error("unrecognized switch '%s'", args[i]);
                continue;

             Lnoarg:
                error("argument expected for switch '%s'", args[i]);
                continue;
            }
        }
        else
        {
version (TARGET_WINDOS) {
            string ext = FileName.ext(p[0..arg.length]);
            if (ext != null && FileName.compare(ext, "exe") == 0)
            {
                global.params.objname = arg[(p - arg.ptr)..$];
                continue;
            }
}
            files.push(cast(void*)new String(arg[(p - arg.ptr)..$]));
        }
    }
    if (global.errors)
    {
        fatal();
    }
    if (files.dim == 0)
    {        usage();
        return EXIT_FAILURE;
    }

    if (!setdebuglib)
        global.params.debuglibname = global.params.defaultlibname;

version (TARGET_OSX) {
    global.params.pic = 1;
}

    if (global.params.release)
    {
        global.params.useInvariants = 0;
        global.params.useIn = 0;
        global.params.useOut = 0;
        global.params.useAssert = 0;
        global.params.useArrayBounds = 0;
        global.params.useSwitchError = 0;
    }
    
    if (noboundscheck)
	    global.params.useArrayBounds = 0;
    
    if (global.params.run)
        global.params.quiet = 1;

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

    if (!global.params.obj || global.params.lib)
        global.params.link = 0;

    if (global.params.link)
    {
        global.params.exefile = global.params.objname;
        global.params.oneobj = 1;
        if (global.params.objname)
        {
            /* Use this to name the one object file with the same
             * name as the exe file.
             */
            global.params.objname = FileName.forceExt(global.params.objname, global.obj_ext).toChars();

            /* If output directory is given, use that path rather than
             * the exe file path.
             */
            if (global.params.objdir)
            {
				string name = FileName.name(global.params.objname);
                global.params.objname = FileName.combine(global.params.objdir, name);
            }
        }
    }
    else if (global.params.lib)
    {
        global.params.libname = global.params.objname;
        global.params.objname = null;

        // Haven't investigated handling these options with multiobj
        if (!global.params.cov && !global.params.trace)
            global.params.multiobj = 1;
    }
    else if (global.params.run)
    {
        error("flags conflict with -run");
        fatal();
    }
    else
    {
        if (global.params.objname && files.dim > 1)
        {
            global.params.oneobj = 1;
            //error("multiple source files, but only one .obj name");
            //fatal();
        }
    }
    if (global.params.isX86_64)
    {
        VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86_64");
        VersionCondition.addPredefinedGlobalIdent("X86_64");
        VersionCondition.addPredefinedGlobalIdent("D_LP64");
version (TARGET_WINDOS) {
        VersionCondition.addPredefinedGlobalIdent("Win64");
}
    }
    else
    {
        VersionCondition.addPredefinedGlobalIdent("D_InlineAsm");
        VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86");
        VersionCondition.addPredefinedGlobalIdent("X86");
version (TARGET_WINDOS) {
        VersionCondition.addPredefinedGlobalIdent("Win32");
}
    }
    if (global.params.doDocComments)
        VersionCondition.addPredefinedGlobalIdent("D_Ddoc");
    if (global.params.cov)
        VersionCondition.addPredefinedGlobalIdent("D_Coverage");
    if (global.params.pic)
        VersionCondition.addPredefinedGlobalIdent("D_PIC");
version (DMDV2) {
    if (global.params.useUnitTests)
        VersionCondition.addPredefinedGlobalIdent("unittest");
}

    // Initialization
    Type.init();
    Id.initialize();
    initPrecedence();
	global.initClasssym();

    backend_init();

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

    // Build import search path
    if (global.params.imppath)
    {
        for (int i = 0; i < global.params.imppath.dim; i++)
        {
            string path = (cast(String)global.params.imppath.data[i]).str;
            string[] a = FileName.splitPath(path);

            global.path ~= a;
        }
    }

    // Build string import search path
    if (global.params.fileImppath)
    {
        for (int i = 0; i < global.params.fileImppath.dim; i++)
        {
            string path = (cast(String)global.params.fileImppath.data[i]).str;
            string[] a = FileName.splitPath(path);
			
            global.filePath ~= a;
        }
    }

    // Create Modules
    Array modules = new Array();
    modules.reserve(files.dim);
    int firstmodule = 1;
    for (int i = 0; i < files.dim; i++)
    {
        string ext;
        string name;

		String s = cast(String) files.data[i];
        string mp = s.str;

version (Windows) {
		char[] copy = null;
        // Convert / to \ so linker will work
        foreach (j, c; mp)
        {
            if (c == '/') {
				if (copy is null) copy = mp.dup;
                copy[j] = '\\';
			}
        }

		if (copy !is null) mp = assumeUnique(copy);
}
		string p = mp;
		
        p = FileName.name(p);                // strip path
        ext = FileName.ext(p);
		
        if (ext.length != 0)
        {   /* Deduce what to do with a file based on its extension
             */
            if (FileName.equals(ext, global.obj_ext))
            {
                global.params.objfiles.push(files.data[i]);
                libmodules.push(files.data[i]);
                continue;
            }

            if (FileName.equals(ext, global.lib_ext))
            {
                global.params.libfiles.push(files.data[i]);
                libmodules.push(files.data[i]);
                continue;
            }

            if (ext == global.ddoc_ext)
            {
                global.params.ddocfiles.push(files.data[i]);
                continue;
            }
            
			if (FileName.equals(ext, global.json_ext))
			{
				global.params.doXGeneration = 1;
				global.params.xfilename = (cast(immutable(char)*)files.data[i])[0..0];
				continue;
			}

version (TARGET_WINDOS)
{
            if (FileName.equals(ext, "res"))
            {
                global.params.resfile = (cast(immutable(char)*)files.data[i])[0..0];		/// !!!
                continue;
            }

            if (FileName.equals(ext, "def"))
            {
                global.params.deffile = (cast(immutable(char)*)files.data[i])[0..0];
                continue;
            }

            if (FileName.equals(ext, "exe"))
            {
                assert(0);        // should have already been handled
            }
}

            /* Examine extension to see if it is a valid
             * D source file extension
             */
            if (FileName.equals(ext, global.mars_ext) ||
                FileName.equals(ext, global.hdr_ext) ||
                FileName.equals(ext, "dd") ||
                FileName.equals(ext, "htm") ||
                FileName.equals(ext, "html") ||
                FileName.equals(ext, "xhtml"))
            {
				immutable(char)* e = ext.ptr;
                e--;                        // skip onto '.'
                assert(*e == '.');
				
				immutable(char)* n = p.ptr;

                name = n[0..(e-n)];	// strip extension

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

        /* At this point, name is the D source file name stripped of
         * its path and extension.
         */

        Identifier id = new Identifier(name, TOK.TOKreserved);
        m = new Module((cast(String) files.data[i]).str, id, global.params.doDocComments, global.params.doHdrGeneration);
        modules.push(cast(void*)m);

        if (firstmodule)
        {
			global.params.objfiles.push(cast(void*)m.objfile.name);
            firstmodule = 0;
        }
    }

    // Read files
//version = ASYNCREAD;
version (ASYNCREAD) {
    // Multi threaded
    AsyncRead *aw = AsyncRead.create(modules.dim);
    for (i = 0; i < modules.dim; i++)
    {
        m = cast(Module *)modules.data[i];
        aw.addFile(m.srcfile);
    }
    aw.start();
} else {
    // Single threaded
    for (int i = 0; i < modules.dim; i++)
    {
        m = cast(Module)modules.data[i];
        m.read(Loc(0));
    }
}

    // Parse files
    int anydocfiles = 0;
    for (int i = 0; i < modules.dim; i++)
    {
        m = cast(Module)modules.data[i];
        if (global.params.verbose)
            writef("parse     %s\n", m.toChars());
        if (!global.rootModule)
            global.rootModule = m;
        m.importedFrom = m;
        if (!global.params.oneobj || i == 0 || m.isDocFile)
            m.deleteObjFile();
version (ASYNCREAD) {
        if (aw.read(i))
        {
            error("cannot read file %s", m.srcfile.name.toChars());
        }
}

        m.parse();
        if (m.isDocFile)
        {
            anydocfiles = 1;
            m.gendocfile();

            // Remove m from list of modules
            modules.remove(i);
            i--;

            // Remove m's object file from list of object files
            for (int j = 0; j < global.params.objfiles.dim; j++)
            {
                if (m.objfile.name.str == (cast(FileName)global.params.objfiles.data[j]).str)
                {
                    global.params.objfiles.remove(j);
                    break;
                }
            }

            if (global.params.objfiles.dim == 0)
                global.params.link = 0;
        }
    }
version (ASYNCREAD) {
    AsyncRead.dispose(aw);
}

    if (anydocfiles && modules.dim &&
        (global.params.oneobj || global.params.objname))
    {
        error("conflicting Ddoc and obj generation options");
        fatal();
    }
    if (global.errors)
        fatal();
version (_DH)
{
    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 (i = 0; i < modules.dim; i++)
        {
            m = cast(Module)modules.data[i];
            if (global.params.verbose)
                writef("import    %s\n", m.toChars());
            m.genhdrfile();
        }
    }
    if (global.errors)
        fatal();
}
	//load all unconditional imports for better symbol resolving
	for (int i = 0; i < modules.dim; i++)
	{
		m = cast(Module)modules.data[i];
		if (global.params.verbose)
			writef("importall %s\n", m.toChars());
		m.importAll(null);
	}
	if (global.errors)
		fatal();
		
    // Do semantic analysis
    for (int i = 0; i < modules.dim; i++)
    {
        m = cast(Module)modules.data[i];
        if (global.params.verbose)
            writef("semantic  %s\n", m.toChars());
        m.semantic();
    }
    if (global.errors)
        fatal();
	
    // Do pass 2 semantic analysis
    for (int i = 0; i < modules.dim; i++)
    {
        m = cast(Module)modules.data[i];
        if (global.params.verbose)
            writef("semantic2 %s\n", m.toChars());
        m.semantic2();
    }
    if (global.errors)
        fatal();

    // Do pass 3 semantic analysis
    for (int i = 0; i < modules.dim; i++)
    {
        m = cast(Module)modules.data[i];
        if (global.params.verbose)
            writef("semantic3 %s\n", m.toChars());
        m.semantic3();
    }
    if (global.errors)
        fatal();
	
    if (global.params.moduleDeps !is null)
    {
        assert(global.params.moduleDepsFile !is null);

        File deps = new File(global.params.moduleDepsFile);
        OutBuffer ob = global.params.moduleDeps;
        deps.setbuffer(cast(void*)ob.data, ob.offset);
        deps.writev();
    }


    // 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)
        {
            // Do pass 3 semantic analysis on all imported modules,
            // since otherwise functions in them cannot be inlined
            for (int i = 0; i < global.amodules.dim; i++)
            {
                m = cast(Module)global.amodules.data[i];
                if (global.params.verbose)
                    writef("semantic3 %s\n", m.toChars());
                m.semantic3();
            }
            if (global.errors)
                fatal();
        }

        for (int i = 0; i < modules.dim; i++)
        {
            m = cast(Module)modules.data[i];
            if (global.params.verbose)
                writef("inline scan %s\n", m.toChars());
				
            m.inlineScan();
        }
    }
    if (global.errors)
        fatal();

    Library library = null;
    if (global.params.lib)
    {
        library = new Library();
        library.setFilename(global.params.objdir, global.params.libname);

        // Add input object and input library files to output library
        for (int i = 0; i < libmodules.dim; i++)
        {
            string p = (cast(String)libmodules.data[i]).str;
            library.addObject(p, null, 0);
        }
    }

    // Generate output files
	if (global.params.doXGeneration)
		json_generate(modules);
    
    if (global.params.oneobj)
    {
        for (int i = 0; i < modules.dim; i++)
        {
            m = cast(Module)modules.data[i];
            if (global.params.verbose)
                writef("code      %s\n", m.toChars());
            if (i == 0)
                obj_start(cast(char*)toStringz(m.srcfile.toChars()));
            m.genobjfile(0);
            if (!global.errors && global.params.doDocComments)
                m.gendocfile();
        }
        if (!global.errors && modules.dim)
        {
            obj_end(library, (cast(Module)modules.data[0]).objfile);
        }
    }
    else
    {
        for (int i = 0; i < modules.dim; i++)
        {
            m = cast(Module)modules.data[i];
            if (global.params.verbose)
                writef("code      %s\n", m.toChars());
            if (global.params.obj)
            {  
				obj_start(cast(char*)toStringz(m.srcfile.toChars()));
                m.genobjfile(global.params.multiobj);
                obj_end(library, m.objfile);
                obj_write_deferred(library);
            }
            if (global.errors)
            {
                if (!global.params.lib)
                    m.deleteObjFile();
            }
            else
            {
                if (global.params.doDocComments)
                    m.gendocfile();
            }
        }
    }		

    if (global.params.lib && !global.errors)
        library.write();

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

    if (!global.params.objfiles.dim)
    {
        if (global.params.link)
            error("no object files to link");
    }
    else
    {
        if (global.params.link)
            status = runLINK();

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

                /* Delete .obj files and .exe file
                 */
                for (int i = 0; i < modules.dim; i++)
                {
                    m = cast(Module)modules.data[i];
                    m.deleteObjFile();
                    if (global.params.oneobj)
                        break;
                }
                deleteExeFile();
            }
        }
    }

    return status;
}