示例#1
0
        /// <summary>
        /// Compile code
        /// </summary>
        /// <param name="outputtype">Type of the assembly to produce</param>
        /// <param name="code">C# code</param>
        /// <param name="moduleName">Name of the generated module</param>
        /// <param name="options">Compilation options</param>
        /// <returns></returns>
        public Assembly Compile(CompiledOutputType outputtype, 
            string code,
            string moduleName,
            CompileOptions options)
        {
            string codeOutputDirectory = null;
            if (options != null && !string.IsNullOrEmpty(options.CodeOutputDirectory))
            {
                Directory.CreateDirectory(options.CodeOutputDirectory);
                codeOutputDirectory = Path.GetFullPath(options.CodeOutputDirectory);
            }

            // Check that we have .NET
            if (MaxAvailableNETVersion < _neededVersion)
                throw new ParsingException(string.Format(
                                              ".NET v{0}.{1} is required to compile this script. .NET v{2}.{3} is installed.",
                                              _neededVersion.Major, _neededVersion.Minor, MaxAvailableNETVersion.Major, MaxAvailableNETVersion.Minor));

            // .NET 3.0 missing method fix
            bool prov35 = (MaxAvailableNETVersion >= new Version(3, 5));

            // Proceed with the gory details
            CompilerParameters param = new CompilerParameters();
            if (outputtype == CompiledOutputType.InMemoryAssembly )
            {
                param.GenerateExecutable = false;

                // If codeoutput directory is set, generate DLLs with debug info for <code> debuggin
                param.GenerateInMemory = false;
                param.IncludeDebugInformation = (codeOutputDirectory != null);
            }
            else
            {
                param.GenerateExecutable = (outputtype == CompiledOutputType.ConsoleExe || outputtype == CompiledOutputType.WindowsExe);
                param.GenerateInMemory = false;
                param.IncludeDebugInformation = (codeOutputDirectory != null);
                param.OutputAssembly = moduleName;

                var dir = Path.GetDirectoryName(moduleName);
                if (!string.IsNullOrEmpty(dir) && (codeOutputDirectory != null) && !Directory.Exists(dir))
                    Directory.CreateDirectory(dir);

            }

            param.WarningLevel = 0;
            switch (outputtype)
            {
                case CompiledOutputType.Library:
                    param.CompilerOptions += " /target:library";
                    break;
                case CompiledOutputType.ConsoleExe:
                    param.CompilerOptions += " /target:exe";
                    break;
                case CompiledOutputType.WindowsExe:
                    param.CompilerOptions += " /target:winexe";
                    break;
            }
            CompilerResults cr;
            List<string> toDelete = new List<string>();
            Dictionary<string,bool> embedded=new Dictionary<string, bool>();

            try
            {
                if (options!=null && options.Manifest!=null)
                {
                    // Only C# 3.5 can do manifests & icons separately. If compiled with .NET 2.0 there will be no file version
                    if (prov35)
                    {
                        string wm = getTempFilename(codeOutputDirectory, str_manifest);
                        toDelete.Add(wm);
                        File.WriteAllBytes(wm, options.Manifest);
                        string wi = getTempFilename(codeOutputDirectory, str_icon);
                        toDelete.Add(wi);
                        File.WriteAllBytes(wi, options.Icon);
                        param.CompilerOptions += " " + Utils.QuoteArg("/win32manifest:" + wm) + " " + Utils.QuoteArg("/win32icon:" + wi);
                    }
                    else
                    {
                        string w32 = getTempFilename(codeOutputDirectory, str_w32resources);
                        toDelete.Add(w32);
                        File.WriteAllBytes(w32, options.Compiled);
                        param.Win32Resource = w32;
                    }
                }

                if (options!=null && options.EntryPoint != null)
                    param.MainClass = options.EntryPoint;

                bool allStrong = true;
                Dictionary<string,string> resources=new Dictionary<string, string>();
                foreach (Ref r in _references)
                {
                    string location = r.From;
                    string dllName = string.Empty;
                    if (!string.IsNullOrEmpty(r.Name))
                    {
                        dllName = new AssemblyName(r.Name).Name + ".dll";
                    }

                    if (string.IsNullOrEmpty(location) && options != null && options.StreamProvider != null)
                    {
                        using (var v = options.StreamProvider(dllName))
                            if (v != null)
                            {
                                location = getTempFilename(codeOutputDirectory, str_references+Path.GetFileName(dllName));
                                toDelete.Add(location);
                                using (FileStream fs = new FileStream(location, FileMode.Create, FileAccess.Write, FileShare.Read))
                                    v.WriteTo(fs);
                            }
                    }
                    if (string.IsNullOrEmpty(location))
                    {
                        location = r.ForceLoad(_verboseWriter).Location;
                    }
                    if (string.IsNullOrEmpty(location))
                        throw new FileNotFoundException(string.Format("Referenced assembly {0} could not be found", r));

                    param.ReferencedAssemblies.Add(location);

                    if (options != null && moduleName != null && r.Embed && (CompiledOutputType.WindowsExe == outputtype || CompiledOutputType.ConsoleExe == outputtype) && options.StreamProvider != null)
                    {
                        MemoryStream v= options.StreamProvider(dllName + ".gz");
                        if (!string.IsNullOrEmpty(r.Name))
                        {
                            var n = new AssemblyName(r.Name);
                            if (n.GetPublicKeyToken() == null || n.GetPublicKeyToken().Length == 0)
                            {
                                _verboseWriter.WriteVerbose("Compile> Embedded assembly " + r.Name + " does not have a strong name.");
                                allStrong = false;
                            }
                        }
                        if (!embedded.ContainsKey(dllName))
                        {
                            string prefix = "XSharper.Embedded.Assemblies.";
                            // Let's be nice here, and compress the dll a bit
                            string complocation = createResource(resources, v, location, prefix + dllName, codeOutputDirectory, str_resources + prefix.Replace(".", "\\"));
                            if (complocation != null)
                                toDelete.Add(complocation);
                            embedded[dllName] = true;
                        }
                    }
                }
                // If user wanted any files, add them too
                if (options != null && options.FilesToEmbed != null)
                {
                    foreach (var pair in options.FilesToEmbed)
                    {
                        string name = (pair.IsAssembly) ? "XSharper.Embedded.Assemblies." : "XSharper.Embedded.Files.";
                        if (pair.IsAssembly)
                        {
                            _verboseWriter.WriteVerbose("Compile> Getting assembly name of " + pair.Location);
                            var pkt = AssemblyName.GetAssemblyName(pair.Location).GetPublicKeyToken();
                            if (pkt == null || pkt.Length == 0)
                            {
                                _verboseWriter.WriteVerbose("Compile> Embedded assembly " + pair.Location + " does not have a strong name.");
                                allStrong = false;
                            }
                        }
                        string complocation = createResource(resources, null, pair.Location, name + new FileInfo(pair.StreamName).Name, codeOutputDirectory, str_resources + name.Replace(".", "\\"));
                        if (complocation != null)
                            toDelete.Add(complocation);
                    }

                    if (allStrong)
                    {
                        string location = getTempFilename(codeOutputDirectory, str_resources+"XSharper\\Embedded\\Assemblies\\AllStrongName.flag");
                        toDelete.Add(location);
                        using (FileStream fs = new FileStream(location, FileMode.Create, FileAccess.Write, FileShare.Read))
                            fs.WriteByte((byte) '1');
                    }
                }

                if (codeOutputDirectory != null)
                    param.TempFiles = new TempFileCollection(codeOutputDirectory, true);
                foreach (var resource in resources)
                    param.CompilerOptions += " \"/res:" + resource.Key + "," + resource.Value + "\" ";
                if (options!=null && options.ExtraOptions != null)
                    param.CompilerOptions += " " + options.ExtraOptions;

                CSharpCodeProvider prov;
                if (!prov35)
                    prov=new CSharpCodeProvider();
                else
                {
                    Dictionary<string, string> providerOptions = new Dictionary<string, string>();
                    if (Environment.Version.Major>=4)
                        providerOptions.Add("CompilerVersion", string.Format("v{0}", "4.0"));
                    else
                        providerOptions.Add("CompilerVersion", string.Format("v{0}", "3.5"));

                    // Must do it this way, to prevent loading errors on machines with .net 2.0
                    prov = (CSharpCodeProvider) Activator.CreateInstance(typeof (CSharpCodeProvider), new object[] {providerOptions});
                }

                _verboseWriter.WriteVerbose("Compile> " + Dump.ToDump(param));
                cr = prov.CompileAssemblyFromSource(param, code);

                // Do some beautification
                if (outputtype != CompiledOutputType.InMemoryAssembly && codeOutputDirectory != null)
                    beautifyOutput(prov35, outputtype, options, param, resources, moduleName, _neededVersion);

                _verboseWriter.WriteVerbose("Compile> -- Completed --");
                // Fire compilation
                if (cr.Errors != null && cr.Errors.Count != 0)
                {
                    if (File.Exists(cr.PathToAssembly))
                        File.Delete(cr.PathToAssembly);
                    StringBuilder sb= new StringBuilder();
                    sb.Append("C# code compilation error:\n");
                    string[] lines = code.Split('\n');
                    foreach (CompilerError error in cr.Errors)
                    {
                        if (error != null)
                        {
                            string line = (error.Line >= 1 && error.Line <= lines.Length) ? lines[error.Line - 1] : "???";
                            sb.AppendLine(string.Format("Line: {0}\nError: {1}", line.TrimEnd(), error.ErrorText));
                        }
                    }
                    _verboseWriter.WriteVerbose("Compile> Errors: " + sb.ToString());

                    throw new ParsingException(sb.ToString());
                }

                if (outputtype == CompiledOutputType.InMemoryAssembly)
                {
                    byte[] asmData = File.ReadAllBytes(cr.PathToAssembly);
                    File.Delete(cr.PathToAssembly);
                    Assembly a=Assembly.Load(asmData);
                    return a;
                }
            }
            finally
            {
                if (string.IsNullOrEmpty(codeOutputDirectory) || outputtype == CompiledOutputType.InMemoryAssembly)
                    foreach (string na in toDelete)
                        File.Delete(na);
            }
            return outputtype == CompiledOutputType.InMemoryAssembly ? cr.CompiledAssembly : null;
        }
示例#2
0
        /// <summary>
        /// Compile code
        /// </summary>
        /// <param name="outputtype">Type of the assembly to produce</param>
        /// <param name="code">C# code</param>
        /// <param name="moduleName">Name of the generated module</param>
        /// <param name="options">Compilation options</param>
        /// <returns></returns>
        public Assembly Compile(CompiledOutputType outputtype,
                                string code,
                                string moduleName,
                                CompileOptions options)
        {
            string codeOutputDirectory = null;

            if (options != null && !string.IsNullOrEmpty(options.CodeOutputDirectory))
            {
                Directory.CreateDirectory(options.CodeOutputDirectory);
                codeOutputDirectory = Path.GetFullPath(options.CodeOutputDirectory);
            }

            // Check that we have .NET
            if (MaxAvailableNETVersion < _neededVersion)
            {
                throw new ParsingException(string.Format(
                                               ".NET v{0}.{1} is required to compile this script. .NET v{2}.{3} is installed.",
                                               _neededVersion.Major, _neededVersion.Minor, MaxAvailableNETVersion.Major, MaxAvailableNETVersion.Minor));
            }

            // .NET 3.0 missing method fix
            bool prov35 = (MaxAvailableNETVersion >= new Version(3, 5));



            // Proceed with the gory details
            CompilerParameters param = new CompilerParameters();

            if (outputtype == CompiledOutputType.InMemoryAssembly)
            {
                param.GenerateExecutable = false;

                // If codeoutput directory is set, generate DLLs with debug info for <code> debuggin
                param.GenerateInMemory        = false;
                param.IncludeDebugInformation = (codeOutputDirectory != null);
            }
            else
            {
                param.GenerateExecutable      = (outputtype == CompiledOutputType.ConsoleExe || outputtype == CompiledOutputType.WindowsExe);
                param.GenerateInMemory        = false;
                param.IncludeDebugInformation = (codeOutputDirectory != null);
                param.OutputAssembly          = moduleName;

                var dir = Path.GetDirectoryName(moduleName);
                if (!string.IsNullOrEmpty(dir) && (codeOutputDirectory != null) && !Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
            }

            param.WarningLevel = 0;
            switch (outputtype)
            {
            case CompiledOutputType.Library:
                param.CompilerOptions += " /target:library";
                break;

            case CompiledOutputType.ConsoleExe:
                param.CompilerOptions += " /target:exe";
                break;

            case CompiledOutputType.WindowsExe:
                param.CompilerOptions += " /target:winexe";
                break;
            }
            CompilerResults           cr;
            List <string>             toDelete = new List <string>();
            Dictionary <string, bool> embedded = new Dictionary <string, bool>();



            try
            {
                if (options != null && options.Manifest != null)
                {
                    // Only C# 3.5 can do manifests & icons separately. If compiled with .NET 2.0 there will be no file version
                    if (prov35)
                    {
                        string wm = getTempFilename(codeOutputDirectory, str_manifest);
                        toDelete.Add(wm);
                        File.WriteAllBytes(wm, options.Manifest);
                        string wi = getTempFilename(codeOutputDirectory, str_icon);
                        toDelete.Add(wi);
                        File.WriteAllBytes(wi, options.Icon);
                        param.CompilerOptions += " " + Utils.QuoteArg("/win32manifest:" + wm) + " " + Utils.QuoteArg("/win32icon:" + wi);
                    }
                    else
                    {
                        string w32 = getTempFilename(codeOutputDirectory, str_w32resources);
                        toDelete.Add(w32);
                        File.WriteAllBytes(w32, options.Compiled);
                        param.Win32Resource = w32;
                    }
                }

                if (options != null && options.EntryPoint != null)
                {
                    param.MainClass = options.EntryPoint;
                }

                bool allStrong = true;
                Dictionary <string, string> resources = new Dictionary <string, string>();
                foreach (Ref r in _references)
                {
                    string location = r.From;
                    string dllName  = string.Empty;
                    if (!string.IsNullOrEmpty(r.Name))
                    {
                        dllName = new AssemblyName(r.Name).Name + ".dll";
                    }

                    if (string.IsNullOrEmpty(location) && options != null && options.StreamProvider != null)
                    {
                        using (var v = options.StreamProvider(dllName))
                            if (v != null)
                            {
                                location = getTempFilename(codeOutputDirectory, str_references + Path.GetFileName(dllName));
                                toDelete.Add(location);
                                using (FileStream fs = new FileStream(location, FileMode.Create, FileAccess.Write, FileShare.Read))
                                    v.WriteTo(fs);
                            }
                    }
                    if (string.IsNullOrEmpty(location))
                    {
                        location = r.ForceLoad(_verboseWriter).Location;
                    }
                    if (string.IsNullOrEmpty(location))
                    {
                        throw new FileNotFoundException(string.Format("Referenced assembly {0} could not be found", r));
                    }

                    param.ReferencedAssemblies.Add(location);

                    if (options != null && moduleName != null && r.Embed && (CompiledOutputType.WindowsExe == outputtype || CompiledOutputType.ConsoleExe == outputtype) && options.StreamProvider != null)
                    {
                        MemoryStream v = options.StreamProvider(dllName + ".gz");
                        if (!string.IsNullOrEmpty(r.Name))
                        {
                            var n = new AssemblyName(r.Name);
                            if (n.GetPublicKeyToken() == null || n.GetPublicKeyToken().Length == 0)
                            {
                                _verboseWriter.WriteVerbose("Compile> Embedded assembly " + r.Name + " does not have a strong name.");
                                allStrong = false;
                            }
                        }
                        if (!embedded.ContainsKey(dllName))
                        {
                            string prefix = "XSharper.Embedded.Assemblies.";
                            // Let's be nice here, and compress the dll a bit
                            string complocation = createResource(resources, v, location, prefix + dllName, codeOutputDirectory, str_resources + prefix.Replace(".", "\\"));
                            if (complocation != null)
                            {
                                toDelete.Add(complocation);
                            }
                            embedded[dllName] = true;
                        }
                    }
                }
                // If user wanted any files, add them too
                if (options != null && options.FilesToEmbed != null)
                {
                    foreach (var pair in options.FilesToEmbed)
                    {
                        string name = (pair.IsAssembly) ? "XSharper.Embedded.Assemblies." : "XSharper.Embedded.Files.";
                        if (pair.IsAssembly)
                        {
                            _verboseWriter.WriteVerbose("Compile> Getting assembly name of " + pair.Location);
                            var pkt = AssemblyName.GetAssemblyName(pair.Location).GetPublicKeyToken();
                            if (pkt == null || pkt.Length == 0)
                            {
                                _verboseWriter.WriteVerbose("Compile> Embedded assembly " + pair.Location + " does not have a strong name.");
                                allStrong = false;
                            }
                        }
                        string complocation = createResource(resources, null, pair.Location, name + new FileInfo(pair.StreamName).Name, codeOutputDirectory, str_resources + name.Replace(".", "\\"));
                        if (complocation != null)
                        {
                            toDelete.Add(complocation);
                        }
                    }

                    if (allStrong)
                    {
                        string location = getTempFilename(codeOutputDirectory, str_resources + "XSharper\\Embedded\\Assemblies\\AllStrongName.flag");
                        toDelete.Add(location);
                        using (FileStream fs = new FileStream(location, FileMode.Create, FileAccess.Write, FileShare.Read))
                            fs.WriteByte((byte)'1');
                    }
                }

                if (codeOutputDirectory != null)
                {
                    param.TempFiles = new TempFileCollection(codeOutputDirectory, true);
                }
                foreach (var resource in resources)
                {
                    param.CompilerOptions += " \"/res:" + resource.Key + "," + resource.Value + "\" ";
                }
                if (options != null && options.ExtraOptions != null)
                {
                    param.CompilerOptions += " " + options.ExtraOptions;
                }

                CSharpCodeProvider prov;
                if (!prov35)
                {
                    prov = new CSharpCodeProvider();
                }
                else
                {
                    Dictionary <string, string> providerOptions = new Dictionary <string, string>();
                    if (Environment.Version.Major >= 4)
                    {
                        providerOptions.Add("CompilerVersion", string.Format("v{0}", "4.0"));
                    }
                    else
                    {
                        providerOptions.Add("CompilerVersion", string.Format("v{0}", "3.5"));
                    }

                    // Must do it this way, to prevent loading errors on machines with .net 2.0
                    prov = (CSharpCodeProvider)Activator.CreateInstance(typeof(CSharpCodeProvider), new object[] { providerOptions });
                }

                _verboseWriter.WriteVerbose("Compile> " + Dump.ToDump(param));
                cr = prov.CompileAssemblyFromSource(param, code);

                // Do some beautification
                if (outputtype != CompiledOutputType.InMemoryAssembly && codeOutputDirectory != null)
                {
                    beautifyOutput(prov35, outputtype, options, param, resources, moduleName, _neededVersion);
                }

                _verboseWriter.WriteVerbose("Compile> -- Completed --");
                // Fire compilation
                if (cr.Errors != null && cr.Errors.Count != 0)
                {
                    if (File.Exists(cr.PathToAssembly))
                    {
                        File.Delete(cr.PathToAssembly);
                    }
                    StringBuilder sb = new StringBuilder();
                    sb.Append("C# code compilation error:\n");
                    string[] lines = code.Split('\n');
                    foreach (CompilerError error in cr.Errors)
                    {
                        if (error != null)
                        {
                            string line = (error.Line >= 1 && error.Line <= lines.Length) ? lines[error.Line - 1] : "???";
                            sb.AppendLine(string.Format("Line: {0}\nError: {1}", line.TrimEnd(), error.ErrorText));
                        }
                    }
                    _verboseWriter.WriteVerbose("Compile> Errors: " + sb.ToString());

                    throw new ParsingException(sb.ToString());
                }

                if (outputtype == CompiledOutputType.InMemoryAssembly)
                {
                    byte[] asmData = File.ReadAllBytes(cr.PathToAssembly);
                    File.Delete(cr.PathToAssembly);
                    Assembly a = Assembly.Load(asmData);
                    return(a);
                }
            }
            finally
            {
                if (string.IsNullOrEmpty(codeOutputDirectory) || outputtype == CompiledOutputType.InMemoryAssembly)
                {
                    foreach (string na in toDelete)
                    {
                        File.Delete(na);
                    }
                }
            }
            return(outputtype == CompiledOutputType.InMemoryAssembly ? cr.CompiledAssembly : null);
        }