/// <summary> /// Executes the Drivers Compiler using the specified logging methods. /// </summary> /// <param name="messageHandler">The handler for outputting ordinary messages.</param> /// <param name="warningHandler">The handler for outputting warning messages.</param> /// <param name="errorHandler">The handler for outputting error messages.</param> /// <returns>Returns an error code.</returns> public static ErrorCode Execute( Logger.LogMessageEventHandler messageHandler, Logger.LogWarningEventHandler warningHandler, Logger.LogErrorEventHandler errorHandler) { ErrorCode result = ErrorCode.NoError; Logger.OnLogMessage += messageHandler; Logger.OnLogWarning += warningHandler; Logger.OnLogError += errorHandler; Options.Format(); DateTime startTime = DateTime.Now; Logger.LogMessage("", 0, "Driver compiler started @ " + startTime.ToLongTimeString()); Logger.LogMessage("", 0, "Library path = \"" + Options.LibraryPath + "\""); Logger.LogMessage("", 0, "Output path = \"" + Options.OutputPath + "\""); Logger.LogMessage("", 0, "Tools path = \"" + Options.ToolsPath + "\""); Logger.LogMessage("", 0, "Target architecture = \"" + Options.TargetArchitecture + "\""); Logger.LogMessage("", 0, "Build mode = " + Enum.GetName(typeof(Options.BuildModes), Options.BuildMode)); Logger.LogMessage("", 0, "Link mode = " + Enum.GetName(typeof(Options.LinkModes), Options.LinkMode)); Logger.LogMessage("", 0, "Base address = " + Options.BaseAddress.ToString()); Logger.LogMessage("", 0, "Load offset = " + Options.LoadOffset.ToString()); // IL Library - In a list of libraries returned to the higher-level control app (this app) // from Library Loader // : Type Info - In a list of types in the IL Library // : Field Info - In a list of static and non-static fields in the Type Info // : Method Info - In a list of methods in the Type Info // : Variable Info - In a list of variables in the Method Info // : IL Block - In a list of blocks in the IL Library and held against the origin Method Info // : IL Op - In a list of ops in the IL Block // // ASM Library - In a list of libraries returned to the higher-level control app (this app) // from IL Compiler // : ASM Block - In a list of blocks in the ASM Library and held against the origin IL Block // : ASM Op - In a list of ops in the ASM Block // // Options - Compiler options used throughout the compiler // Library loader - Loads IL Libraries to be compiled // - Type Scanner - Loads all the Type Infos, Field Infos and Method Infos. // IL Compiler - Manages the IL compile stage // - IL Reader - Loads IL ops from IL Methods in IL Types. Also loads plug info. // - IL Preprocessor - Pre-scans IL ops to find things like necessary branching labels. // Also handles injecting any necessary IL ops in such a way that // IL integrity is maintained. // - IL Scanner - Converts IL ops to ASM ops // ASM Compiler - Manages the ASM compile stage // - ASM Preprocessor - Pre-scans the ASM ops to store things like debug info or perform // optimisation // - ASM Processor - Converts ASM ops into ASM text then runs the assembly code compiler (e.g. NASM) // Link Manager - Manages the linker stage. Links together all the object files using "ld". // To think about: // - Try-catch-finally blocks // - GC (inc. wrapping try-finally, calls to inc/dec) // - Release / Debug IL (differences? Potential issues?) // Resultant thoughts from above: // - IL labels based on IL Op index NOT IL op offset // - IL Preprocessor handle injecting any IL ops inc. try-catch-finally, GC stuff and special // class / method stuff (e.g. static variables, static constructors etc.) // - IL Preprocessor needs to maintain the integrity of the IL so that no assumption are made // so that Release mode IL also works // TODO: // - Check for unchanged methods (in IL Preprocessor) and exclude them from recompile Tuple <bool, string> ValidateOptions_Result = Options.Validate(); if (ValidateOptions_Result.Item1) { try { TargetArchitecture.Init(); IL.ILLibrary TheLibrary = LibraryLoader.LoadILLibrary(Options.LibraryPath); CompileResult ILCompileResult = IL.ILCompiler.Compile(TheLibrary); if (ILCompileResult == CompileResult.OK || ILCompileResult == CompileResult.PartialFailure) { CompileResult ASMCompileResult = ASM.ASMCompiler.Compile(TheLibrary); if (ASMCompileResult == CompileResult.OK) { CompileResult LinkResult = LinkManager.Link(TheLibrary); if (LinkResult == CompileResult.OK) { if (ILCompileResult == CompileResult.PartialFailure) { result = ErrorCode.ILCompilerFailed; } //Success Logger.LogMessage("", 0, "Compilation succeeded."); } else { //Fail Logger.LogError(Errors.Linker_LinkFailed_ErrorCode, "", 0, Errors.ErrorMessages[Errors.Linker_LinkFailed_ErrorCode]); result = ErrorCode.LinkerFailed; } } else { //Fail Logger.LogError(Errors.ASMCompiler_CompileFailed_ErrorCode, "", 0, Errors.ErrorMessages[Errors.ASMCompiler_CompileFailed_ErrorCode]); result = ErrorCode.ASMCompilerFailed; } } else { //Fail Logger.LogError(Errors.ILCompiler_CompileFailed_ErrorCode, "", 0, Errors.ErrorMessages[Errors.ILCompiler_CompileFailed_ErrorCode]); result = ErrorCode.ILCompilerFailed; } } catch (NullReferenceException ex) { Logger.LogError(Errors.ILCompiler_NullRefException_ErrorCode, "", 0, string.Format( Errors.ErrorMessages[Errors.ILCompiler_NullRefException_ErrorCode], ex.Message, ex.StackTrace)); result = ErrorCode.ILCompilerFailed; } catch (Exception ex) { Logger.LogError(Errors.ILCompiler_UnexpectedException_ErrorCode, "", 0, string.Format( Errors.ErrorMessages[Errors.ILCompiler_UnexpectedException_ErrorCode], ex.Message, ex.StackTrace)); result = ErrorCode.ILCompilerFailed; } } else { //Fail Logger.LogError(Errors.PreReqs_OptionsInvalid_ErrorCode, "", 0, string.Format( Errors.ErrorMessages[Errors.PreReqs_OptionsInvalid_ErrorCode], ValidateOptions_Result.Item2)); result = ErrorCode.InvalidOptions; } DateTime endTime = DateTime.Now; Logger.LogMessage("", 0, "Driver compiler finished @ " + endTime.ToLongTimeString()); Logger.LogMessage("", 0, " Compile time : " + (endTime - startTime).ToString()); Logger.LogMessage("", 0, " Error code : " + System.Enum.GetName(typeof(ErrorCode), result)); return(result); }