Example #1
0
        static int Main(string[] args)
        {
            CommandLineApplication app = new CommandLineApplication();

            app.HelpOption("-? | -h | --help");
            app.ThrowOnUnexpectedArgument = false;

            // Required arguments
            CommandOption OutputFileOption = app.Option(
                "-f | --file <OUTPUT_FILE>",
                "The output file to write to.",
                CommandOptionType.SingleValue
                ).IsRequired();

            // Compilation-related arguments
            CommandOption <Compiler.DotNetVersion> DotNetVersionOption = app.Option <Compiler.DotNetVersion>(
                "-d | --dotnet | --dotnet-framework <DOTNET_VERSION>",
                "The Dotnet Framework version to target (net35 or net40).",
                CommandOptionType.SingleValue
                );

            DotNetVersionOption.Validators.Add(new MustBeDotNetVersionValidator());
            CommandOption OutputKindOption = app.Option(
                "-o | --output-kind <OUTPUT_KIND>",
                "The OutputKind to use (dll or console).",
                CommandOptionType.SingleValue
                );

            OutputKindOption.Validators.Add(new MustBeOutputKindValidator());
            CommandOption PlatformOption = app.Option(
                "-p | --platform <PLATFORM>",
                "The Platform to use (AnyCpy, x86, or x64).",
                CommandOptionType.SingleValue
                );

            PlatformOption.Validators.Add(new MustBePlatformValidator());
            CommandOption NoOptimizationOption = app.Option(
                "-n | --no-optimization",
                "Don't use source code optimization.",
                CommandOptionType.NoValue
                );
            CommandOption AssemblyNameOption = app.Option(
                "-a | --assembly-name <ASSEMBLY_NAME>",
                "The name of the assembly to be generated.",
                CommandOptionType.SingleValue
                );

            AssemblyNameOption.Validators.Add(new MustBeIdentifierValidator());

            // Source-related arguments
            CommandOption SourceFileOption = app.Option(
                "-s | --source-file <SOURCE_FILE>",
                "The source code to compile.",
                CommandOptionType.SingleValue
                ).Accepts(v => v.ExistingFile());
            CommandOption ClassNameOption = app.Option(
                "-c | --class-name <CLASS_NAME>",
                "The name of the class to be generated.",
                CommandOptionType.SingleValue
                );

            ClassNameOption.Validators.Add(new MustBeIdentifierValidator());

            CommandOption ConfuseOption = app.Option(
                "--confuse <CONFUSEREX_PROJECT_FILE>",
                "The ConfuserEx ProjectFile configuration.",
                CommandOptionType.SingleValue
                ).Accepts(v => v.ExistingFile());

            app.OnExecute(() =>
            {
                Compiler.CompilationRequest request = new Compiler.CompilationRequest();
                // Compilation options
                if (!SetRequestDirectories(ref request))
                {
                    SharpGenConsole.PrintFormattedErrorLine("Unable to specify CompilationRequest directories");
                    app.ShowHelp();
                    return(-1);
                }
                if (!SetRequestDotNetVersion(DotNetVersionOption, ref request))
                {
                    SharpGenConsole.PrintFormattedErrorLine("Invalid DotNetVersion specified.");
                    app.ShowHelp();
                    return(-2);
                }
                if (!SetRequestOutputKind(OutputKindOption, OutputFileOption, ref request))
                {
                    SharpGenConsole.PrintFormattedErrorLine("Invalid OutputKind specified.");
                    app.ShowHelp();
                    return(-3);
                }
                if (!SetRequestPlatform(PlatformOption, ref request))
                {
                    SharpGenConsole.PrintFormattedErrorLine("Invalid Platform specified.");
                    app.ShowHelp();
                    return(-4);
                }
                if (!SetRequestOptimization(NoOptimizationOption, ref request))
                {
                    SharpGenConsole.PrintFormattedErrorLine("Invalid NoOptimization specified.");
                    app.ShowHelp();
                    return(-5);
                }
                if (!SetRequestAssemblyName(AssemblyNameOption, ref request))
                {
                    SharpGenConsole.PrintFormattedErrorLine("Invalid AssemblyName specified.");
                    app.ShowHelp();
                    return(-6);
                }
                if (!SetRequestReferences(ref request))
                {
                    SharpGenConsole.PrintFormattedErrorLine("Unable to set CompilationRequest references.");
                    app.ShowHelp();
                    return(-7);
                }
                if (!SetRequestEmbeddedResources(ref request))
                {
                    SharpGenConsole.PrintFormattedErrorLine("Unable to set CompilationRequest resources.");
                    app.ShowHelp();
                    return(-8);
                }

                // Source options
                if (!SetRequestSource(SourceFileOption, ClassNameOption, app.RemainingArguments, ref request))
                {
                    SharpGenConsole.PrintFormattedErrorLine("Unable to create source code for request.");
                    app.ShowHelp();
                    return(-9);
                }

                // Compile
                SharpGenConsole.PrintFormattedProgressLine("Compiling source: ");
                SharpGenConsole.PrintInfoLine(request.Source);
                try
                {
                    byte[] compiled = Compiler.Compile(request);

                    // Write to file
                    string path = Path.Combine(Common.SharpGenOutputDirectory, OutputFileOption.Value());
                    File.WriteAllBytes(path, compiled);

                    if (ConfuseOption.HasValue())
                    {
                        ConfuserProject project    = new ConfuserProject();
                        System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
                        string ProjectFile         = String.Format(
                            File.ReadAllText(ConfuseOption.Value()),
                            Common.SharpGenOutputDirectory,
                            Common.SharpGenOutputDirectory,
                            OutputFileOption.Value()
                            );
                        doc.Load(new StringReader(ProjectFile));
                        project.Load(doc);
                        project.ProbePaths.Add(Common.Net35Directory);
                        project.ProbePaths.Add(Common.Net40Directory);

                        SharpGenConsole.PrintFormattedProgressLine("Confusing assembly...");
                        ConfuserParameters parameters = new ConfuserParameters();
                        parameters.Project            = project;
                        parameters.Logger             = new ConfuserConsoleLogger();
                        Directory.SetCurrentDirectory(Common.SharpGenRefsDirectory);
                        ConfuserEngine.Run(parameters).Wait();
                    }

                    SharpGenConsole.PrintFormattedHighlightLine("Compiled assembly written to: " + path);
                }
                catch (CompilerException e)
                {
                    SharpGenConsole.PrintFormattedErrorLine(e.Message);
                    return(-10);
                }
                catch (ConfuserException e)
                {
                    SharpGenConsole.PrintFormattedErrorLine("Confuser Exception: " + e.Message);
                    return(-11);
                }
                return(0);
            });
            return(app.Execute(args));
        }
Example #2
0
        public static byte[] Compile(CompilationRequest request)
        {
            // Gather SyntaxTrees for compilation
            List <SourceSyntaxTree> sourceSyntaxTrees = Directory.GetFiles(request.SourceDirectory, "*.cs", SearchOption.AllDirectories)
                                                        .Select(F => new SourceSyntaxTree {
                FileName = F, SyntaxTree = CSharpSyntaxTree.ParseText(File.ReadAllText(F), new CSharpParseOptions())
            })
                                                        .ToList();
            List <SyntaxTree> compilationTrees = sourceSyntaxTrees.Select(S => S.SyntaxTree).ToList();

            SyntaxTree sourceTree = CSharpSyntaxTree.ParseText(request.Source, new CSharpParseOptions());

            compilationTrees.Add(sourceTree);

            // Use specified OutputKind and Platform
            CSharpCompilationOptions options = new CSharpCompilationOptions(outputKind: request.OutputKind, optimizationLevel: OptimizationLevel.Release, platform: request.Platform);
            // Compile to obtain SemanticModel
            CSharpCompilation compilation = CSharpCompilation.Create(
                request.AssemblyName == null ? Path.GetRandomFileName() : request.AssemblyName,
                compilationTrees,
                request.References.Where(R => R.Framework == request.TargetDotNetVersion).Where(R => R.Enabled).Select(R =>
            {
                string folder = (request.TargetDotNetVersion == DotNetVersion.Net35 ? request.ReferenceDirectory + "net35" + Path.DirectorySeparatorChar : request.ReferenceDirectory + "net40" + Path.DirectorySeparatorChar);
                return(MetadataReference.CreateFromFile(folder + R.File));
            }).ToList(),
                options
                );

            // Perform source code optimization, removing unused types
            if (request.Optimize)
            {
                // Find all Types used by the generated compilation
                List <INamedTypeSymbol> usedTypes = new List <INamedTypeSymbol>();
                GetUsedTypesRecursively(compilation, sourceTree, ref usedTypes, ref sourceSyntaxTrees);
                usedTypes = usedTypes.Distinct().ToList();
                List <string> usedTypeNames = usedTypes.Select(T => GetFullyQualifiedTypeName(T)).ToList();
                // SharpGenConsole.PrintInfoLine("usedTypes: " + String.Join(",", usedTypeNames));

                // Filter SyntaxTrees to trees that define a used Type, otherwise the tree is not needed in this compilation
                compilationTrees = sourceSyntaxTrees.Where(SST => SyntaxTreeDefinesUsedType(compilation, SST.SyntaxTree, usedTypeNames))
                                   .Select(SST => SST.SyntaxTree)
                                   .ToList();

                // Removed unused Using statements from the additional entrypoint source
                List <string> usedNamespaceNames = GetUsedTypes(compilation, sourceTree)
                                                   .Select(T => GetFullyQualifiedContainingNamespaceName(T)).Distinct().ToList();
                // SharpGenConsole.PrintInfoLine("usedNamespaces: " + String.Join(",", usedNamespaceNames));
                List <SyntaxNode> unusedUsingDirectives = sourceTree.GetRoot().DescendantNodes().Where(N =>
                {
                    return(N.Kind() == SyntaxKind.UsingDirective && !usedNamespaceNames.Contains(((UsingDirectiveSyntax)N).Name.ToFullString()));
                }).ToList();
                sourceTree = sourceTree.GetRoot().RemoveNodes(unusedUsingDirectives, SyntaxRemoveOptions.KeepNoTrivia).SyntaxTree;

                // Compile again, with unused SyntaxTrees and unused using statements removed
                SharpGenConsole.PrintFormattedProgressLine("Compiling optimized source: ");
                SharpGenConsole.PrintInfoLine(sourceTree.ToString());
                compilationTrees.Add(sourceTree);
                compilation = CSharpCompilation.Create(
                    request.AssemblyName == null ? Path.GetRandomFileName() : request.AssemblyName,
                    compilationTrees,
                    request.References.Where(R => R.Framework == request.TargetDotNetVersion).Where(R => R.Enabled).Select(R =>
                {
                    string folder = (request.TargetDotNetVersion == DotNetVersion.Net35 ? request.ReferenceDirectory + "net35" + Path.DirectorySeparatorChar : request.ReferenceDirectory + "net40" + Path.DirectorySeparatorChar);
                    return(MetadataReference.CreateFromFile(folder + R.File));
                }).ToList(),
                    options
                    );
            }

            // Emit compilation
            EmitResult emitResult;

            byte[] ILbytes = null;
            using (var ms = new MemoryStream())
            {
                emitResult = compilation.Emit(
                    ms,
                    manifestResources: request.EmbeddedResources.Where(ER =>
                {
                    return(request.Platform == Platform.AnyCpu || ER.Platform == Platform.AnyCpu || ER.Platform == request.Platform);
                }).Where(ER => ER.Enabled).Select(ER =>
                {
                    return(new ResourceDescription(ER.Name, () => File.OpenRead(request.ResourceDirectory + ER.File), true));
                }).ToList()
                    );
                if (emitResult.Success)
                {
                    ms.Flush();
                    ms.Seek(0, SeekOrigin.Begin);
                    ILbytes = ms.ToArray();
                }
                else
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (Diagnostic d in emitResult.Diagnostics)
                    {
                        sb.AppendLine(d.ToString());
                    }
                    throw new CompilerException("CompilationErrors: " + Environment.NewLine + sb);
                }
            }
            return(ILbytes);
        }