From 8ccc12d642d1104bf4c1249a02a82d8af5d6efe0 Mon Sep 17 00:00:00 2001 From: Tedd Hansen Date: Sat, 2 Feb 2008 02:35:56 +0000 Subject: Added OpenSim.32BitLaunch.exe that can be used on 64-bit systems to run OpenSim in 32-bit mode. Added VISUAL BASIC.NET-support //cs, //lsl and //vb as first characters of script will determine what compiler is used. Compile warnings are no longer treated as errors. Script will still run. Added a few useless and useful config options: Write script source to harddisk for debug, Default compile language, Allowed compilers (languages), compile in release or debug mode, clean up old scripts on startup Loads of warnings for incorrect config --- .../DotNetEngine/Compiler/LSL/Compiler.cs | 255 ++++++++++++++++++--- .../ScriptEngine/DotNetEngine/ScriptManager.cs | 11 +- 2 files changed, 230 insertions(+), 36 deletions(-) (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine') diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs index 2adc060..d3f2873 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/LSL/Compiler.cs @@ -28,9 +28,12 @@ using System; using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Reflection; using Microsoft.CSharp; +using Microsoft.VisualBasic; namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL { @@ -44,45 +47,192 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL // Assembly is compiled using LSL_BaseClass as base. Look at debug C# code file created when LSL script is compiled for full details. // - private LSL2CSConverter LSL_Converter = new LSL2CSConverter(); - private CSharpCodeProvider codeProvider = new CSharpCodeProvider(); + internal enum enumCompileType + { + lsl = 0, + cs = 1, + vb = 2 + } + private enumCompileType DefaultCompileLanguage; + private bool WriteScriptSourceToDebugFile; + private bool CompileWithDebugInformation; + private bool CleanUpOldScriptsOnStartup; + private System.Collections.Generic.Dictionary AllowedCompilers = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + private System.Collections.Generic.Dictionary LanguageMapping = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + + private string FilePrefix; + private string ScriptEnginesPath = "ScriptEngines"; + + private static LSL2CSConverter LSL_Converter = new LSL2CSConverter(); + private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider(); + private static VBCodeProvider VBcodeProvider = new VBCodeProvider(); + private static UInt64 scriptCompileCounter = 0; private static int instanceID = new Random().Next(0, int.MaxValue); - // Implemented due to peer preassure --- will cause garbage in ScriptEngines folder ;) + // Implemented due to peer preassure --- will cause garbage in ScriptEngines folder ;) - //private ICodeCompiler icc = codeProvider.CreateCompiler(); - public string CompileFromFile(string LSOFileName) + public Common.ScriptEngineBase.ScriptEngine m_scriptEngine; + public Compiler(Common.ScriptEngineBase.ScriptEngine scriptEngine) { - switch (Path.GetExtension(LSOFileName).ToLower()) - { - case ".txt": - case ".lsl": - Common.ScriptEngineBase.Common.SendToDebug("Source code is LSL, converting to CS"); - return CompileFromLSLText(File.ReadAllText(LSOFileName)); - case ".cs": - Common.ScriptEngineBase.Common.SendToDebug("Source code is CS"); - return CompileFromCSText(File.ReadAllText(LSOFileName)); - default: - throw new Exception("Unknown script type."); + m_scriptEngine = scriptEngine; + ReadConfig(); + } + public bool in_startup = true; + public void ReadConfig() + { + WriteScriptSourceToDebugFile = m_scriptEngine.ScriptConfigSource.GetBoolean("WriteScriptSourceToDebugFile", true); + CompileWithDebugInformation = m_scriptEngine.ScriptConfigSource.GetBoolean("CompileWithDebugInformation", true); + CleanUpOldScriptsOnStartup = m_scriptEngine.ScriptConfigSource.GetBoolean("CleanUpOldScriptsOnStartup", true); + + // Get file prefix from scriptengine name and make it file system safe: + FilePrefix = m_scriptEngine.ScriptEngineName; + foreach (char c in Path.GetInvalidFileNameChars()) + { + FilePrefix = FilePrefix.Replace(c, '_'); + } + // First time we start? + if (in_startup) + { + in_startup = false; + DeleteOldFiles(); + } + + LanguageMapping.Add("cs", enumCompileType.cs); + LanguageMapping.Add("vb", enumCompileType.lsl); + LanguageMapping.Add("lsl", enumCompileType.vb); + + // Allowed compilers + string allowedCompilers = m_scriptEngine.ScriptConfigSource.GetString("AllowedCompilers", "lsl;cs;vb"); + AllowedCompilers.Clear(); + foreach (string strl in allowedCompilers.Split(';')) + { + string strlan = strl.Trim(" \t".ToCharArray()).ToLower(); + if (!LanguageMapping.ContainsKey(strlan)) + { + m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Config error. Compiler is unable to recongnize language type \"" + strl + "\" specified in \"AllowedCompilers\"."); + } + AllowedCompilers.Add(strlan, true); + } + if (AllowedCompilers.Count == 0) + m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Config error. Compiler could not recognize any language in \"AllowedCompilers\". Scripts will not be executed!"); + + // Default language + string defaultCompileLanguage = m_scriptEngine.ScriptConfigSource.GetString("DefaultCompileLanguage", "lsl").ToLower(); + + // Is this language recognized at all? + if (!LanguageMapping.ContainsKey(defaultCompileLanguage)) + m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Config error. Default language specified in \"DefaultCompileLanguage\" is not recognized as a valid language. Scripts may not be executed!"); + + // Is this language in allow-list? + if (!AllowedCompilers.ContainsKey(defaultCompileLanguage)) + { + m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, + "Config error. Default language \"" + defaultCompileLanguage + "\"specified in \"DefaultCompileLanguage\" is not in list of \"AllowedCompilers\". Scripts may not be executed!"); + } + else + { + // LANGUAGE IS IN ALLOW-LIST + DefaultCompileLanguage = LanguageMapping[defaultCompileLanguage]; + } + + // We now have an allow-list, a mapping list, and a default language + + } + + private void DeleteOldFiles() + { + + // CREATE FOLDER IF IT DOESNT EXIST + if (!Directory.Exists(ScriptEnginesPath)) + { + try + { + Directory.CreateDirectory(ScriptEnginesPath); + } + catch (Exception ex) + { + m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Exception trying to create ScriptEngine directory \"" + ScriptEnginesPath + "\": " + ex.ToString()); + } + } + + foreach (string file in Directory.GetFiles(ScriptEnginesPath)) + { + m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "FILE FOUND: " + file); + + if (file.ToLower().StartsWith(FilePrefix + "_compiled_") || + file.ToLower().StartsWith(FilePrefix + "_source_")) + { + try + { + File.Delete(file); + } + catch (Exception ex) + { + m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Exception trying delete old script file \"" + file + "\": " + ex.ToString()); + } + + } } + } + ////private ICodeCompiler icc = codeProvider.CreateCompiler(); + //public string CompileFromFile(string LSOFileName) + //{ + // switch (Path.GetExtension(LSOFileName).ToLower()) + // { + // case ".txt": + // case ".lsl": + // Common.ScriptEngineBase.Common.SendToDebug("Source code is LSL, converting to CS"); + // return CompileFromLSLText(File.ReadAllText(LSOFileName)); + // case ".cs": + // Common.ScriptEngineBase.Common.SendToDebug("Source code is CS"); + // return CompileFromCSText(File.ReadAllText(LSOFileName)); + // default: + // throw new Exception("Unknown script type."); + // } + //} + /// /// Converts script from LSL to CS and calls CompileFromCSText /// /// LSL script /// Filename to .dll assembly - public string CompileFromLSLText(string Script) + public string PerformScriptCompile(string Script) { - if (Script.Substring(0, 4).ToLower() == "//c#") + enumCompileType l = DefaultCompileLanguage; + + + if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture)) + l = enumCompileType.cs; + if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture)) + l = enumCompileType.vb; + if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture)) + l = enumCompileType.lsl; + + if (!AllowedCompilers.ContainsKey(l.ToString())) + { + // Not allowed to compile to this language! + string errtext = String.Empty; + errtext += "The compiler for language \"" + l.ToString() + "\" is not in list of allowed compilers. Script will not be executed!"; + throw new Exception(errtext); + } + + string compileScript; + + if (l == enumCompileType.lsl) { - return CompileFromCSText(Script); + // Its LSL, convert it to C# + compileScript = LSL_Converter.Convert(Script); + l = enumCompileType.cs; } else { - return CompileFromCSText(LSL_Converter.Convert(Script)); + // We don't need to convert + compileScript = Script; } + return CompileFromCSorVBText(Script, l); } /// @@ -90,36 +240,45 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL /// /// CS script /// Filename to .dll assembly - public string CompileFromCSText(string Script) + internal string CompileFromCSorVBText(string Script, enumCompileType lang) { + string ext = "." + lang.ToString(); + // Output assembly name scriptCompileCounter++; string OutFile = Path.Combine("ScriptEngines", - "DotNetScript_" + instanceID.ToString() + "_" + scriptCompileCounter.ToString() + ".dll"); + FilePrefix + "_compiled_" + instanceID.ToString() + "_" + scriptCompileCounter.ToString() + ".dll"); try { File.Delete(OutFile); } catch (Exception e) { - Console.WriteLine("Exception attempting to delete old compiled script: " + e.ToString()); + //m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString()); + throw new Exception("Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString()); } //string OutFile = Path.Combine("ScriptEngines", "SecondLife.Script.dll"); // DEBUG - write source to disk - try - { - File.WriteAllText( - Path.Combine("ScriptEngines", "debug_" + Path.GetFileNameWithoutExtension(OutFile) + ".cs"), Script); - } - catch + if (WriteScriptSourceToDebugFile) { + try + { + File.WriteAllText( + Path.Combine("ScriptEngines", FilePrefix + "_source_" + Path.GetFileNameWithoutExtension(OutFile) + ext), + Script); + } + catch + { + } } // Do actual compile CompilerParameters parameters = new CompilerParameters(); + parameters.IncludeDebugInformation = true; + // Add all available assemblies foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) { @@ -136,11 +295,29 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL //parameters.ReferencedAssemblies.Add("OpenSim.Region.Environment"); parameters.GenerateExecutable = false; parameters.OutputAssembly = OutFile; - parameters.IncludeDebugInformation = false; - CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, Script); + parameters.IncludeDebugInformation = CompileWithDebugInformation; + parameters.WarningLevel = 4; + parameters.TreatWarningsAsErrors = false; + CompilerResults results; + switch (lang) + { + case enumCompileType.vb: + results = VBcodeProvider.CompileAssemblyFromSource(parameters, Script); + break; + case enumCompileType.cs: + results = CScodeProvider.CompileAssemblyFromSource(parameters, Script); + break; + default: + throw new Exception("Compiler is not able to recongnize language type \"" + lang.ToString() + "\""); + } + + // Check result // Go through errors - // TODO: Return errors to user somehow + + // + // WARNINGS AND ERRORS + // if (results.Errors.Count > 0) { string errtext = String.Empty; @@ -150,10 +327,22 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL ", Error Number: " + CompErr.ErrorNumber + ", '" + CompErr.ErrorText + "'\r\n"; } - throw new Exception(errtext); + if (!File.Exists(OutFile)) + { + throw new Exception(errtext); + } } + // + // NO ERRORS, BUT NO COMPILED FILE + // + if (!File.Exists(OutFile)) + { + string errtext = String.Empty; + errtext += "No compile error. But not able to locate compiled file."; + throw new Exception(errtext); + } return OutFile; } } diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs index 8030a32..f6c9e30 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs @@ -49,13 +49,18 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine // UNLOAD SCRIPT // PROVIDE SCRIPT WITH ITS INTERFACE TO OpenSim - private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler(); + private Compiler.LSL.Compiler LSLCompiler; public override void _StartScript(uint localID, LLUUID itemID, string Script) { - //IScriptHost root = host.GetRoot(); m_scriptEngine.Log.Debug(m_scriptEngine.ScriptEngineName, "ScriptManager StartScript: localID: " + localID + ", itemID: " + itemID); + // First time start? Lets fire up our compiler... + if (LSLCompiler == null) + LSLCompiler = new Compiler.LSL.Compiler(m_scriptEngine); + + //IScriptHost root = host.GetRoot(); + // We will initialize and start the script. // It will be up to the script itself to hook up the correct events. string ScriptSource = String.Empty; @@ -65,7 +70,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine try { // Compile (We assume LSL) - ScriptSource = LSLCompiler.CompileFromLSLText(Script); + ScriptSource = LSLCompiler.PerformScriptCompile(Script); #if DEBUG long before; -- cgit v1.1